From eb486f545a5134488689f178462530483cb9b478 Mon Sep 17 00:00:00 2001 From: Simon Urli Date: Tue, 2 Dec 2025 17:41:36 +0100 Subject: [PATCH 1/3] XWIKI-14494: Java scheduler job coming from an extension is not rescheduled when the extension is upgraded * Introduce an event to inform that a classloader has been reset * Trigger the event whenever an extension is uninstalled --- .../xwiki-commons-classloader-api/pom.xml | 5 +++ .../internal/ClassLoaderResetedEvent.java | 42 +++++++++++++++++++ .../checkstyle/checkstyle-suppressions.xml | 2 +- .../JarExtensionJobFinishingListener.java | 18 ++++---- 4 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetedEvent.java diff --git a/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/pom.xml b/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/pom.xml index 94f7c851f9..0595dc2b6e 100644 --- a/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/pom.xml +++ b/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/pom.xml @@ -55,6 +55,11 @@ commons-io commons-io + + org.xwiki.commons + xwiki-commons-observation-api + ${project.version} + diff --git a/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetedEvent.java b/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetedEvent.java new file mode 100644 index 0000000000..561dc617b9 --- /dev/null +++ b/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetedEvent.java @@ -0,0 +1,42 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.xwiki.classloader.internal; + +import org.xwiki.observation.event.Event; +import org.xwiki.stability.Unstable; + +/** + * Event triggered whenever the class loaders needs to be dropped (e.g. after an extension is uninstalled). + * + * The {@code source} sent along with the event should be the namespace of the classloader. + * + * @version $Id$ + * @since 17.1.0 + * @since 18.0.0RC1 + */ +@Unstable +public class ClassLoaderResetedEvent implements Event +{ + @Override + public boolean matches(Object otherEvent) + { + return otherEvent instanceof ClassLoaderResetedEvent; + } +} diff --git a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/checkstyle/checkstyle-suppressions.xml b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/checkstyle/checkstyle-suppressions.xml index fb59c370be..a59d278515 100644 --- a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/checkstyle/checkstyle-suppressions.xml +++ b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/checkstyle/checkstyle-suppressions.xml @@ -25,5 +25,5 @@ "http://www.puppycrawl.com/dtds/suppressions_1_0.dtd"> - + diff --git a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionJobFinishingListener.java b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionJobFinishingListener.java index 5582020add..24796acc7b 100644 --- a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionJobFinishingListener.java +++ b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionJobFinishingListener.java @@ -36,6 +36,7 @@ import org.slf4j.Logger; import org.xwiki.classloader.ClassLoaderManager; +import org.xwiki.classloader.internal.ClassLoaderResetedEvent; import org.xwiki.component.annotation.Component; import org.xwiki.context.Execution; import org.xwiki.context.ExecutionContext; @@ -51,6 +52,7 @@ import org.xwiki.job.event.JobFinishingEvent; import org.xwiki.job.event.JobStartedEvent; import org.xwiki.observation.EventListener; +import org.xwiki.observation.ObservationManager; import org.xwiki.observation.event.Event; /** @@ -120,6 +122,9 @@ private void add(String namespace) @Inject private Logger logger; + @Inject + private ObservationManager observationManager; + @Override public String getName() { @@ -257,32 +262,31 @@ private void onJobFinishedEvent() if (collection != null) { if (collection.rootNamespace) { // Unload extensions - unloadJARsFromNamespace(null, null); + unloadJARsFromNamespace(null); // Drop class loaders this.jarExtensionClassLoader.dropURLClassLoaders(); initializeExtensions(null); + this.observationManager.notify(new ClassLoaderResetedEvent(), null); } else if (collection.namespaces != null) { for (String namespace : collection.namespaces) { // Unload extensions - unloadJARsFromNamespace(namespace, null); + unloadJARsFromNamespace(namespace); // Drop class loader this.jarExtensionClassLoader.dropURLClassLoader(namespace); initializeExtensions(namespace); + this.observationManager.notify(new ClassLoaderResetedEvent(), namespace); } } } } - private void unloadJARsFromNamespace(String namespace, Map> unloadedExtensions) + private void unloadJARsFromNamespace(String namespace) { - Map> unloadedExtensionsMap = unloadedExtensions; - if (unloadedExtensionsMap == null) { - unloadedExtensionsMap = new HashMap<>(); - } + Map> unloadedExtensionsMap = new HashMap<>(); // Load extensions from local repository Collection installedExtensions; From 8dcfd9fe14e2bed026838e3295733f0f3ab5bdae Mon Sep 17 00:00:00 2001 From: Simon Urli Date: Wed, 3 Dec 2025 11:13:01 +0100 Subject: [PATCH 2/3] XWIKI-14494: Java scheduler job coming from an extension is not rescheduled when the extension is upgraded * Include namespace directly in the event * Fix doc * Fix checkstyle warning and remove old unecessary checkstyles ignores --- .../internal/ClassLoaderResetEvent.java | 73 +++++++++++++++++++ .../internal/ClassLoaderResetedEvent.java | 42 ----------- .../pom.xml | 22 ------ .../checkstyle/checkstyle-suppressions.xml | 29 -------- .../internal/handler/JarExtensionHandler.java | 2 +- .../JarExtensionJobFinishingListener.java | 8 +- 6 files changed, 79 insertions(+), 97 deletions(-) create mode 100644 xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetEvent.java delete mode 100644 xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetedEvent.java delete mode 100644 xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/checkstyle/checkstyle-suppressions.xml diff --git a/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetEvent.java b/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetEvent.java new file mode 100644 index 0000000000..ca1178711d --- /dev/null +++ b/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetEvent.java @@ -0,0 +1,73 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.xwiki.classloader.internal; + +import java.util.Objects; + +import org.xwiki.observation.event.Event; +import org.xwiki.stability.Unstable; + +/** + * Event triggered whenever a class loader has been dropped + * (see {@link org.xwiki.classloader.ClassLoaderManager#dropURLClassLoader(String)}) and reloaded. This is used for + * example when a JAR extension is uninstalled. Note that {@link org.xwiki.classloader.ClassLoaderManager} is not + * responsible for triggering this, as the trigger needs to be performed after the classloader reload. + * + * @version $Id$ + * @since 17.1.0 + * @since 18.0.0RC1 + */ +@Unstable +public class ClassLoaderResetEvent implements Event +{ + private final String namespace; + + /** + * Default constructor for the root classloader. + */ + public ClassLoaderResetEvent() + { + this(null); + } + + /** + * Default constructor when the event is triggered for a specific namespace. + * @param namespace the namespace of the reset classloader. + */ + public ClassLoaderResetEvent(String namespace) + { + this.namespace = namespace; + } + + /** + * @return the namespace the event is triggered for. + */ + public String getNamespace() + { + return namespace; + } + + @Override + public boolean matches(Object otherEvent) + { + return otherEvent instanceof ClassLoaderResetEvent classLoaderResetedEvent + && Objects.equals(namespace, classLoaderResetedEvent.namespace); + } +} diff --git a/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetedEvent.java b/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetedEvent.java deleted file mode 100644 index 561dc617b9..0000000000 --- a/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetedEvent.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.xwiki.classloader.internal; - -import org.xwiki.observation.event.Event; -import org.xwiki.stability.Unstable; - -/** - * Event triggered whenever the class loaders needs to be dropped (e.g. after an extension is uninstalled). - * - * The {@code source} sent along with the event should be the namespace of the classloader. - * - * @version $Id$ - * @since 17.1.0 - * @since 18.0.0RC1 - */ -@Unstable -public class ClassLoaderResetedEvent implements Event -{ - @Override - public boolean matches(Object otherEvent) - { - return otherEvent instanceof ClassLoaderResetedEvent; - } -} diff --git a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/pom.xml b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/pom.xml index 99216e4b55..76321f85bd 100644 --- a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/pom.xml +++ b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/pom.xml @@ -33,9 +33,6 @@ XWiki Commons - Extension - Handler - JAR 0.81 - - ${basedir}/src/checkstyle/checkstyle-suppressions.xml - @@ -79,23 +76,4 @@ test - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - default - - - org/xwiki/extension/jar/internal/handler/JarExtensionHandler.java - - - - - - - diff --git a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/checkstyle/checkstyle-suppressions.xml b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/checkstyle/checkstyle-suppressions.xml deleted file mode 100644 index a59d278515..0000000000 --- a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/checkstyle/checkstyle-suppressions.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - diff --git a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionHandler.java b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionHandler.java index 9efbfb7e18..388ad649cc 100644 --- a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionHandler.java +++ b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionHandler.java @@ -110,7 +110,7 @@ public static boolean isSupported(String type) type.equals(JarExtensionHandler.JAR) || type.equals(JarExtensionHandler.WEBJAR) || type.equals(JarExtensionHandler.WEBJAR_NODE) - ); + ); } /** diff --git a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionJobFinishingListener.java b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionJobFinishingListener.java index 24796acc7b..30d706b184 100644 --- a/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionJobFinishingListener.java +++ b/xwiki-commons-core/xwiki-commons-extension/xwiki-commons-extension-handlers/xwiki-commons-extension-handler-jar/src/main/java/org/xwiki/extension/jar/internal/handler/JarExtensionJobFinishingListener.java @@ -36,7 +36,7 @@ import org.slf4j.Logger; import org.xwiki.classloader.ClassLoaderManager; -import org.xwiki.classloader.internal.ClassLoaderResetedEvent; +import org.xwiki.classloader.internal.ClassLoaderResetEvent; import org.xwiki.component.annotation.Component; import org.xwiki.context.Execution; import org.xwiki.context.ExecutionContext; @@ -64,6 +64,8 @@ @Component @Singleton @Named("JarExtensionJobFinishingListener") +// Fan out of 21 +@SuppressWarnings("checkstyle:ClassFanOutComplexity") public class JarExtensionJobFinishingListener implements EventListener { private static final class UninstalledExtensionCollection @@ -268,7 +270,7 @@ private void onJobFinishedEvent() this.jarExtensionClassLoader.dropURLClassLoaders(); initializeExtensions(null); - this.observationManager.notify(new ClassLoaderResetedEvent(), null); + this.observationManager.notify(new ClassLoaderResetEvent(), null); } else if (collection.namespaces != null) { for (String namespace : collection.namespaces) { // Unload extensions @@ -278,7 +280,7 @@ private void onJobFinishedEvent() this.jarExtensionClassLoader.dropURLClassLoader(namespace); initializeExtensions(namespace); - this.observationManager.notify(new ClassLoaderResetedEvent(), namespace); + this.observationManager.notify(new ClassLoaderResetEvent(namespace), null); } } } From 47020c26bd54c1bff8b472d2c73d85a0c202ba0f Mon Sep 17 00:00:00 2001 From: Simon Urli Date: Wed, 3 Dec 2025 11:52:25 +0100 Subject: [PATCH 3/3] XWIKI-14494: Java scheduler job coming from an extension is not rescheduled when the extension is upgraded * Fix event match condition --- .../org/xwiki/classloader/internal/ClassLoaderResetEvent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetEvent.java b/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetEvent.java index ca1178711d..5ffae68f14 100644 --- a/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetEvent.java +++ b/xwiki-commons-core/xwiki-commons-classloader/xwiki-commons-classloader-api/src/main/java/org/xwiki/classloader/internal/ClassLoaderResetEvent.java @@ -68,6 +68,7 @@ public String getNamespace() public boolean matches(Object otherEvent) { return otherEvent instanceof ClassLoaderResetEvent classLoaderResetedEvent - && Objects.equals(namespace, classLoaderResetedEvent.namespace); + && (namespace == null + || Objects.equals(namespace, classLoaderResetedEvent.namespace)); } }