This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit f51380286efcdcdae9b7a5a905819c9e74935d10 Author: Martin Desruisseaux <[email protected]> AuthorDate: Sat Nov 7 15:37:55 2026 +0100 Add Enterprise JavaBeans (EJB) support in `org.apache.sis.web` module. https://issues.apache.org/jira/browse/SIS-640 --- endorsed/build.gradle.kts | 10 ++-- .../main/org/apache/sis/setup/Configuration.java | 12 ++--- .../main/org/apache/sis/system/DaemonThread.java | 7 +-- .../main/org/apache/sis/system/Shutdown.java | 31 ++++++++--- .../src/org.apache.sis.web/main/module-info.java | 25 ++++++--- .../org/apache/sis/web/jakarta/JavaBeanHook.java | 60 ++++++++++++++++++++++ .../org/apache/sis/web/jakarta/package-info.java | 5 +- .../org/apache/sis/web/javaee/JavaBeanHook.java | 60 ++++++++++++++++++++++ .../org/apache/sis/web/javaee/package-info.java | 5 +- netbeans-project/ivy.xml | 4 ++ 10 files changed, 189 insertions(+), 30 deletions(-) diff --git a/endorsed/build.gradle.kts b/endorsed/build.gradle.kts index 9cb53dd0ee..a7b4a7ca4c 100644 --- a/endorsed/build.gradle.kts +++ b/endorsed/build.gradle.kts @@ -70,9 +70,13 @@ dependencies { compileOnly(libs.aws.s3) compileOnly(drivers.postgres) runtimeOnly(drivers.hsql) - compileOnly(group = "jakarta.servlet", name = "jakarta.servlet-api", version = "6.1.0") - compileOnly(group = "javax.servlet", name = "javax.servlet-api", version = "4.0.1") - compileOnly(group = "org.osgi", name = "osgi.core", version = "8.0.0") + compileOnly(group = "jakarta.annotation", name = "jakarta.annotation-api", version = "3.0.0") + compileOnly(group = "jakarta.servlet", name = "jakarta.servlet-api", version = "6.1.0") + compileOnly(group = "jakarta.ejb", name = "jakarta.ejb-api", version = "4.0.1") + compileOnly(group = "javax.annotation", name = "javax.annotation-api", version = "1.3.2") + compileOnly(group = "javax.servlet", name = "javax.servlet-api", version = "4.0.1") + compileOnly(group = "javax.ejb", name = "javax.ejb-api", version = "3.2.2") + compileOnly(group = "org.osgi", name = "osgi.core", version = "8.0.0") // Test dependencies testImplementation(tests.junit5) diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java index 32291aafae..18a401d62b 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java @@ -25,8 +25,6 @@ import javax.sql.DataSource; import java.sql.SQLException; import org.apache.sis.system.Shutdown; import org.apache.sis.system.Environment; -import org.apache.sis.system.SystemListener; -import org.apache.sis.util.logging.Logging; import org.apache.sis.util.internal.shared.MetadataServices; @@ -156,7 +154,7 @@ public final class Configuration { * * class MyClass { * private static DataSource createDataSource() { - * PGSimpleDataSource ds = new PGSimpleDataSource(); + * var ds = new PGSimpleDataSource(); * ds.setDatabaseName("SpatialMetadata"); * // Server default to "localhost". * return ds; @@ -182,7 +180,7 @@ public final class Configuration { * The supplier may return {@code null}, in which case it will be ignored. * @throws IllegalStateException if {@link DataSource} has already be obtained before this method call. * - * @see <a href="https://sis.apache.org/epsg.html#jndi">How to use EPSG geodetic dataset</a> + * @see <a href="https://sis.apache.org/epsg.html#jndi">How to use <abbr>EPSG</abbr> geodetic dataset</a> */ public void setDatabase(final Supplier<DataSource> source) { MetadataServices.getInstance().setDataSource(Objects.requireNonNull(source)); @@ -195,13 +193,13 @@ public final class Configuration { * Any use of Apache <abbr>SIS</abbr> after this method call may have unexpected effects. * In particular, it may cause memory leaks. * - * <h4>When to use</h4> + * <h4>When to shutdown Apache <abbr>SIS</abbr></h4> * This method should generally <strong>not</strong> be invoked, because Apache <abbr>SIS</abbr> registers * itself a {@linkplain Runtime#addShutdownHook(Thread) shutdown hook} to the Java Virtual Machine. * This method may be useful in embedded environments that do not allow the use of shutdown hooks, * or when waiting for the <abbr>JVM</abbr> shutdown is overly conservative. * - * <h4>Complete shutdown of Derby</h4> + * <h4>Complete shutdown of Derby database</h4> * This method shutdowns only the databases used by Apache <abbr>SIS</abbr>. * If Apache Derby is used for the <abbr>EPSG</abbr> database, some Derby daemon threads may still be running. * Those daemons can be ignored in standalone applications, but may need to be stopped in embedded environments. @@ -224,7 +222,7 @@ public final class Configuration { try { Shutdown.stop(Configuration.class); } catch (Exception e) { - Logging.unexpectedException(SystemListener.LOGGER, Configuration.class, "stop", e); + Shutdown.log(Configuration.class, e); } } } diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/DaemonThread.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/DaemonThread.java index 47360d304c..3dbf7585a9 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/DaemonThread.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/DaemonThread.java @@ -18,6 +18,7 @@ package org.apache.sis.system; import java.util.List; import java.util.ArrayList; +import static org.apache.sis.util.internal.shared.Constants.NANOS_PER_MILLISECOND; /** @@ -141,9 +142,9 @@ abstract class DaemonThread extends Thread { t.interrupt(); } while (thread != null) { - final long delay = stopWaitingAt - System.nanoTime(); - if (delay <= 0) break; - thread.join(delay / 1000000); // Convert nanoseconds to milliseconds. + final long delay = (stopWaitingAt - System.nanoTime()) / NANOS_PER_MILLISECOND; + if (delay <= 0) break; // A value of 0 cause `join(…)` to wait forever. + thread.join(delay); thread = thread.previous; } } diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/Shutdown.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/Shutdown.java index d2ce0f08a3..70fabf7124 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/Shutdown.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/Shutdown.java @@ -21,6 +21,7 @@ import java.util.ArrayDeque; import java.util.Objects; import java.util.concurrent.Callable; import org.apache.sis.util.logging.Logging; +import static org.apache.sis.util.internal.shared.Constants.NANOS_PER_SECOND; /** @@ -33,6 +34,8 @@ public final class Shutdown extends Thread { /** * Non-null if a shutdown hook is already registered. That shutdown hook is not necessarily {@link #hook}. * It may be an OSGi or Servlet shutdown hook instead, as notified by {@link #setContainer(String)}. + * + * @see #setContainer(String) */ private static String container; @@ -60,7 +63,7 @@ public final class Shutdown extends Thread { @SuppressWarnings("CallToPrintStackTrace") public void run() { try { - Shutdown.stop((Class<?>) null); + stop((Class<?>) null); } catch (Exception e) { /* * Too late for logging since we are in process of shutting down the Java Virtual Machine. @@ -84,15 +87,18 @@ public final class Shutdown extends Thread { /** * Invoked if the Apache SIS library is executed from an environment that provides its own shutdown hook. * Example of such environments are OSGi and servlet containers. In such case, the shutdown hook will not - * be registered to the JVM {@link Runtime}. + * be registered to the <abbr>JVM</abbr> {@link Runtime}. * * @param env a description of the container. Should contain version information if possible. * Example: {@code "OSGi"} or {@code "JavaServer Web Dev Kit/1.0"}. */ - public static void setContainer(final String env) { + public static void setContainer(String env) { Objects.requireNonNull(env); synchronized (resources) { removeShutdownHook(); // Should not be needed but we are paranoiac. + if (container != null) { + env = container + " & " + env; + } container = env; } } @@ -145,7 +151,7 @@ public final class Shutdown extends Thread { /** * Unregisters the supervisor MBean, executes the disposal tasks and shutdowns the {@code org.apache.sis.util} threads. - * This method may be invoked at JVM shutdown, or if a container like OSGi is unloaded the SIS library. + * This method may be invoked at JVM shutdown, or if a container like OSGi is unloading the <abbr>SIS</abbr> library. * * @param caller the class invoking this method (used for logging purpose), or {@code null} if this method * is invoked at JVM shutdown time (in which case the logging system is not available anymore). @@ -163,7 +169,7 @@ public final class Shutdown extends Thread { } /* * Unregister the MBean before to stop the threads, in order to avoid false alerts - * in the superviror 'warnings()' method. Failure to unregister the MBean is worth + * in the superviror `warnings()` method. Failure to unregister the MBean is worth * to report, but we will do that only after we completed the other shutdown steps. */ Exception exception = null; @@ -194,14 +200,25 @@ public final class Shutdown extends Thread { * but continue the shutdown process anyway. */ try { - Threads.shutdown(System.nanoTime() + 4000); + Threads.shutdown(System.nanoTime() + 3*NANOS_PER_SECOND); } catch (InterruptedException e) { if (caller != null) { - Logging.unexpectedException(SystemListener.LOGGER, caller, "stop", e); + log(caller, e); } } if (exception != null) { throw exception; } } + + /** + * Convenience method for logging an unexpected exception at shutdown time. + * This method assumes that the caller is a method named {@code "shutdown"}. + * + * @param caller the class which is doing the shutdown. + * @param e the exception that occurred during shutdown. + */ + public static void log(final Class<?> caller, final Exception e) { + Logging.unexpectedException(SystemListener.LOGGER, caller, "shutdown", e); + } } diff --git a/endorsed/src/org.apache.sis.web/main/module-info.java b/endorsed/src/org.apache.sis.web/main/module-info.java index e10df4ddf0..edd24615e0 100644 --- a/endorsed/src/org.apache.sis.web/main/module-info.java +++ b/endorsed/src/org.apache.sis.web/main/module-info.java @@ -16,18 +16,21 @@ */ /** - * Support for Apache <abbr>SIS</abbr> execution in the context of web containers. + * Support for Apache <abbr>SIS</abbr> execution in the context of JavaEE or web containers. * This module registers listeners for stopping Apache <abbr>SIS</abbr> background threads - * when a web application using <abbr>SIS</abbr> is undeployed from a web container. + * when a web application or an Enterprise JavaBean (<abbr>EJB</abbr>) using <abbr>SIS</abbr> + * is undeployed from a container. * The listeners in this module are compatible with the following frameworks: * * <ul> - * <li>JavaEE Servlet 4.0 ({@code javax.servlet} package)</li> - * <li>Jakarta Servlet 6.1 ({@code jakarta.servlet} package)</li> - * <li>OGSGi 8.0 ({@code org.osgi.framework} package)</li> + * <li>Jakarta Servlet ({@code jakarta.servlet} package)</li> + * <li>JavaEE Servlet ({@code javax.servlet} package)</li> + * <li>Jakarta Enterprise JavaBeans (<abbr>EJB</abbr>) ({@code jakarta.ejb} package)</li> + * <li>JavaEE <abbr>EJB</abbr> ({@code javax.ejb} package)</li> + * <li>OGSGi ({@code org.osgi.framework} package)</li> * </ul> * - * Web applications should consider adding this module in their dependencies + * Web applications or Enterprise JavaBeans should consider adding this module in their dependencies * if they use Apache <abbr>SIS</abbr> and need clean undeploy while keeping the rest of the container running. * * @author Martin Desruisseaux (Geomatys) @@ -36,8 +39,18 @@ */ module org.apache.sis.web { requires transitive org.apache.sis.util; + + // Servlet (new and old) requires static jakarta.servlet; requires static javax.servlet.api; + + // JavaEE (new and old) + requires static jakarta.annotation; + requires static jakarta.ejb; + requires static java.annotation; + requires static javax.ejb.api; + + // OSGi bundle requires static osgi.core; provides jakarta.servlet.ServletContainerInitializer diff --git a/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/jakarta/JavaBeanHook.java b/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/jakarta/JavaBeanHook.java new file mode 100644 index 0000000000..15b37812dc --- /dev/null +++ b/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/jakarta/JavaBeanHook.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.web.jakarta; + +import jakarta.ejb.Startup; +import jakarta.ejb.Singleton; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import org.apache.sis.system.Shutdown; + + +/** + * Listener for Enterprise JavaBeans, used as a shutdown hook when the <abbr>EJB</abbr> is undeployed. + * This class should not be used directly. + * + * @author Martin Desruisseaux (Geomatys) + */ +@Startup +@Singleton +public final class JavaBeanHook { + /** + * Invoked by reflection. + */ + public JavaBeanHook() { + } + + /** + * Notifies Apache <abbr>SIS</abbr> that the application is initializing. + */ + @PostConstruct + public void initialize() { + Shutdown.setContainer("EJB (Jakarta)"); + } + + /** + * Receives notification that the application is about to be shutdown. + */ + @PreDestroy + public void shutdown() { + try { + Shutdown.stop(getClass()); + } catch (Exception e) { + Shutdown.log(getClass(), e); + } + } +} diff --git a/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/jakarta/package-info.java b/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/jakarta/package-info.java index 8c3d25f7d4..5c99bcb14c 100644 --- a/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/jakarta/package-info.java +++ b/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/jakarta/package-info.java @@ -17,8 +17,9 @@ /** - * All classes having a dependencies to Jakarta ({@code jakarta.servlet} packages). - * This is the replacement of JavaEE ({@code javax.servlet} packages). + * All classes having a dependencies to Jakarta ({@code jakarta.servlet} and {@code jakarta.ejb} packages). + * Jakarta contains Enterprise JavaBeans (<abbr>EJB</abbr>) for business logic and servlet for the web. + * This is the replacement of JavaEE ({@code javax.*} packages). * * @author Martin Desruisseaux (Geomatys) */ diff --git a/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/javaee/JavaBeanHook.java b/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/javaee/JavaBeanHook.java new file mode 100644 index 0000000000..0b97ff8c2c --- /dev/null +++ b/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/javaee/JavaBeanHook.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.web.javaee; + +import javax.ejb.Startup; +import javax.ejb.Singleton; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import org.apache.sis.system.Shutdown; + + +/** + * Listener for Enterprise JavaBeans, used as a shutdown hook when the <abbr>EJB</abbr> is undeployed. + * This class should not be used directly. + * + * @author Martin Desruisseaux (Geomatys) + */ +@Startup +@Singleton +public final class JavaBeanHook { + /** + * Invoked by reflection. + */ + public JavaBeanHook() { + } + + /** + * Notifies Apache <abbr>SIS</abbr> that the application is initializing. + */ + @PostConstruct + public void initialize() { + Shutdown.setContainer("EJB (JavaEE)"); + } + + /** + * Receives notification that the application is about to be shutdown. + */ + @PreDestroy + public void shutdown() { + try { + Shutdown.stop(getClass()); + } catch (Exception e) { + Shutdown.log(getClass(), e); + } + } +} diff --git a/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/javaee/package-info.java b/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/javaee/package-info.java index 739613c974..9137f99f9e 100644 --- a/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/javaee/package-info.java +++ b/endorsed/src/org.apache.sis.web/main/org/apache/sis/web/javaee/package-info.java @@ -17,8 +17,9 @@ /** - * All classes having a dependencies to JavaEE ({@code javax.servlet} packages). - * JavaEE is replaced by Jakarta ({@code jakarta.servlet} packages), but not all applications have migrated. + * All classes having a dependencies to JavaEE ({@code javax.servlet} and {@code javax.ejb} packages). + * JavaEE contains Enterprise JavaBeans (<abbr>EJB</abbr>) for business logic and servlet for the web. + * JavaEE is replaced by Jakarta ({@code jakarta.*} packages), but not all applications have migrated. * This package is provided for web applications that are still using JavaEE. * * @author Martin Desruisseaux (Geomatys) diff --git a/netbeans-project/ivy.xml b/netbeans-project/ivy.xml index c998d5b478..8e329a390f 100644 --- a/netbeans-project/ivy.xml +++ b/netbeans-project/ivy.xml @@ -28,6 +28,10 @@ <dependency org="org.antlr" name="antlr4-maven-plugin" rev="4.13.2"/> <dependency org="javax.servlet" name="javax.servlet-api" rev="4.0.1"/> <dependency org="jakarta.servlet" name="jakarta.servlet-api" rev="6.1.0"/> + <dependency org="javax.ejb" name="javax.ejb-api" rev="3.2.2"/> + <dependency org="jakarta.ejb" name="jakarta.ejb-api" rev="4.0.1"/> + <dependency org="jakarta.annotation" name="jakarta.annotation-api" rev="3.0.0"/> + <dependency org="javax.annotation" name="javax.annotation-api" rev="1.3.2"/> <dependency org="org.osgi" name="osgi.core" rev="8.0.0"/> <dependency org="org.junit.platform" name="junit-platform-launcher" rev="1.10.3"/> <dependency org="org.junit.jupiter" name="junit-jupiter-api" rev="5.10.3"/>
