io.netty.bootstrap.ChannelInitializerExtensions Maven / Gradle / Ivy
/*
* Copyright 2023 The Netty Project
*
* The Netty Project 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:
*
* https://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 io.netty.bootstrap;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLogLevel;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.ServiceLoader;
/**
* The configurable facade that decides what {@link ChannelInitializerExtension}s to load and where to find them.
*/
abstract class ChannelInitializerExtensions {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelInitializerExtensions.class);
private static volatile ChannelInitializerExtensions implementation;
private ChannelInitializerExtensions() {
}
/**
* Get the configuration extensions, which is a no-op implementation by default,
* or a service-loading implementation if the {@code io.netty.bootstrap.extensions} system property is
* {@code serviceload}.
*/
static ChannelInitializerExtensions getExtensions() {
ChannelInitializerExtensions impl = implementation;
if (impl == null) {
synchronized (ChannelInitializerExtensions.class) {
impl = implementation;
if (impl != null) {
return impl;
}
String extensionProp = SystemPropertyUtil.get(ChannelInitializerExtension.EXTENSIONS_SYSTEM_PROPERTY);
logger.debug("-Dio.netty.bootstrap.extensions: {}", extensionProp);
if ("serviceload".equalsIgnoreCase(extensionProp)) {
impl = new ServiceLoadingExtensions(InternalLogLevel.DEBUG, true);
} else if ("log".equalsIgnoreCase(extensionProp)) {
impl = new ServiceLoadingExtensions(InternalLogLevel.INFO, false);
} else {
impl = new EmptyExtensions();
}
implementation = impl;
}
}
return impl;
}
/**
* Get the list of available extensions. The list is unmodifiable.
*/
abstract Collection extensions(ClassLoader cl);
private static final class EmptyExtensions extends ChannelInitializerExtensions {
@Override
Collection extensions(ClassLoader cl) {
return Collections.emptyList();
}
}
private static final class ServiceLoadingExtensions extends ChannelInitializerExtensions {
private final InternalLogLevel logLevel;
private final boolean loadAndCache;
private WeakReference classLoader;
private Collection extensions;
ServiceLoadingExtensions(InternalLogLevel logLevel, boolean loadAndCache) {
this.logLevel = logLevel;
this.loadAndCache = loadAndCache;
}
@SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
@Override
synchronized Collection extensions(ClassLoader cl) {
ClassLoader configured = classLoader == null ? null : classLoader.get();
if (configured == null || configured != cl) {
Collection loaded = serviceLoadExtensions(logLevel, cl);
classLoader = new WeakReference(cl);
extensions = loadAndCache ? loaded : Collections.emptyList();
}
return extensions;
}
private static Collection serviceLoadExtensions(
InternalLogLevel logLevel, ClassLoader cl) {
ArrayList extensions = new ArrayList();
ServiceLoader loader = ServiceLoader.load(
ChannelInitializerExtension.class, cl);
for (ChannelInitializerExtension extension : loader) {
logger.log(logLevel, "Loaded extension: {}", extension.getClass());
extensions.add(extension);
}
if (!extensions.isEmpty()) {
Collections.sort(extensions, new Comparator() {
@Override
public int compare(ChannelInitializerExtension a, ChannelInitializerExtension b) {
return Double.compare(a.priority(), b.priority());
}
});
return Collections.unmodifiableList(extensions);
}
return Collections.emptyList();
}
}
}