This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/main by this push:
new 8ebb151301 Log a status error event instead of an NPE
8ebb151301 is described below
commit 8ebb151301f436dcc147b7e7e05e3c66dd8f4d5c
Author: Gary Gregory <[email protected]>
AuthorDate: Fri Mar 10 10:20:13 2023 -0500
Log a status error event instead of an NPE
See org.apache.logging.log4j.util.OsgiServiceLocator.loadServices(Class,
Lookup, boolean) when a bundle has no valid BundleContext for a service
type.
---
.../logging/log4j/util/OsgiServiceLocator.java | 79 ++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git
a/log4j-api/src/main/java/org/apache/logging/log4j/util/OsgiServiceLocator.java
b/log4j-api/src/main/java/org/apache/logging/log4j/util/OsgiServiceLocator.java
new file mode 100644
index 0000000000..b5ffb41dbd
--- /dev/null
+++
b/log4j-api/src/main/java/org/apache/logging/log4j/util/OsgiServiceLocator.java
@@ -0,0 +1,79 @@
+/*
+ * 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.logging.log4j.util;
+
+import java.lang.invoke.MethodHandles.Lookup;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+import org.apache.logging.log4j.status.StatusLogger;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+public class OsgiServiceLocator {
+
+ private static final boolean OSGI_AVAILABLE = checkOsgiAvailable();
+
+ private static boolean checkOsgiAvailable() {
+ try {
+ /*
+ * OSGI classes of any version can still be present even if Log4j2
does not run in
+ * an OSGI container, hence we check if this class is in a bundle.
+ */
+ final Class< ? > clazz =
Class.forName("org.osgi.framework.FrameworkUtil");
+ return clazz.getMethod("getBundle", Class.class)
+ .invoke(null, OsgiServiceLocator.class) != null;
+ } catch (final ClassNotFoundException | NoSuchMethodException |
LinkageError e) {
+ return false;
+ } catch (final Throwable e) {
+ LowLevelLogUtil.logException("Unknown error checking OSGI
environment.", e);
+ return false;
+ }
+ }
+
+ public static boolean isAvailable() {
+ return OSGI_AVAILABLE;
+ }
+
+ public static <T> Stream<T> loadServices(final Class<T> serviceType, final
Lookup lookup) {
+ return loadServices(serviceType, lookup, true);
+ }
+
+ public static <T> Stream<T> loadServices(final Class<T> serviceType, final
Lookup lookup, final boolean verbose) {
+ final Class<?> lookupClass = Objects.requireNonNull(lookup,
"lookup").lookupClass();
+ final Bundle bundle =
FrameworkUtil.getBundle(Objects.requireNonNull(lookupClass, "lookupClass"));
+ if (bundle != null) {
+ final BundleContext ctx = bundle.getBundleContext();
+ if (ctx == null) {
+ if (verbose) {
+ StatusLogger.getLogger().error(
+ "Unable to load OSGI services: The bundle has no
valid BundleContext for serviceType = {}, lookup = {}, lookupClass = {}, bundle
= {}",
+ serviceType, lookup, lookupClass, bundle);
+ }
+ }
+ try {
+ return ctx.getServiceReferences(serviceType,
null).stream().map(ctx::getService);
+ } catch (Throwable e) {
+ if (verbose) {
+ StatusLogger.getLogger().error("Unable to load OSGI
services for service {}", serviceType, e);
+ }
+ }
+ }
+ return Stream.empty();
+ }
+}