/*
* Copyright 2016 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:
*
* 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 io.netty.util;
import io.netty.util.internal.
ObjectUtil;
import io.netty.util.internal.
PlatformDependent;
import io.netty.util.internal.
SystemPropertyUtil;
import io.netty.util.internal.logging.
InternalLogger;
import io.netty.util.internal.logging.
InternalLoggerFactory;
import java.lang.reflect.
Constructor;
import java.security.
AccessController;
import java.security.
PrivilegedAction;
/**
* This static factory should be used to load {@link ResourceLeakDetector}s as needed
*/
public abstract class
ResourceLeakDetectorFactory {
private static final
InternalLogger logger =
InternalLoggerFactory.
getInstance(
ResourceLeakDetectorFactory.class);
private static volatile
ResourceLeakDetectorFactory factoryInstance = new
DefaultResourceLeakDetectorFactory();
/**
* Get the singleton instance of this factory class.
*
* @return the current {@link ResourceLeakDetectorFactory}
*/
public static
ResourceLeakDetectorFactory instance() {
return
factoryInstance;
}
/**
* Set the factory's singleton instance. This has to be called before the static initializer of the
* {@link ResourceLeakDetector} is called by all the callers of this factory. That is, before initializing a
* Netty Bootstrap.
*
* @param factory the instance that will become the current {@link ResourceLeakDetectorFactory}'s singleton
*/
public static void
setResourceLeakDetectorFactory(
ResourceLeakDetectorFactory factory) {
factoryInstance =
ObjectUtil.
checkNotNull(
factory, "factory");
}
/**
* Returns a new instance of a {@link ResourceLeakDetector} with the given resource class.
*
* @param resource the resource class used to initialize the {@link ResourceLeakDetector}
* @param <T> the type of the resource class
* @return a new instance of {@link ResourceLeakDetector}
*/
public final <T>
ResourceLeakDetector<T>
newResourceLeakDetector(
Class<T>
resource) {
return
newResourceLeakDetector(
resource,
ResourceLeakDetector.
DEFAULT_SAMPLING_INTERVAL);
}
/**
* @deprecated Use {@link #newResourceLeakDetector(Class, int)} instead.
* <p>
* Returns a new instance of a {@link ResourceLeakDetector} with the given resource class.
*
* @param resource the resource class used to initialize the {@link ResourceLeakDetector}
* @param samplingInterval the interval on which sampling takes place
* @param maxActive This is deprecated and will be ignored.
* @param <T> the type of the resource class
* @return a new instance of {@link ResourceLeakDetector}
*/
@
Deprecated
public abstract <T>
ResourceLeakDetector<T>
newResourceLeakDetector(
Class<T>
resource, int
samplingInterval, long
maxActive);
/**
* Returns a new instance of a {@link ResourceLeakDetector} with the given resource class.
*
* @param resource the resource class used to initialize the {@link ResourceLeakDetector}
* @param samplingInterval the interval on which sampling takes place
* @param <T> the type of the resource class
* @return a new instance of {@link ResourceLeakDetector}
*/
@
SuppressWarnings("deprecation")
public <T>
ResourceLeakDetector<T>
newResourceLeakDetector(
Class<T>
resource, int
samplingInterval) {
return
newResourceLeakDetector(
resource,
ResourceLeakDetector.
DEFAULT_SAMPLING_INTERVAL,
Long.
MAX_VALUE);
}
/**
* Default implementation that loads custom leak detector via system property
*/
private static final class
DefaultResourceLeakDetectorFactory extends
ResourceLeakDetectorFactory {
private final
Constructor<?>
obsoleteCustomClassConstructor;
private final
Constructor<?>
customClassConstructor;
DefaultResourceLeakDetectorFactory() {
String customLeakDetector;
try {
customLeakDetector =
AccessController.
doPrivileged(new
PrivilegedAction<
String>() {
@
Override
public
String run() {
return
SystemPropertyUtil.
get("io.netty.customResourceLeakDetector");
}
});
} catch (
Throwable cause) {
logger.
error("Could not access System property: io.netty.customResourceLeakDetector",
cause);
customLeakDetector = null;
}
if (
customLeakDetector == null) {
obsoleteCustomClassConstructor =
customClassConstructor = null;
} else {
obsoleteCustomClassConstructor =
obsoleteCustomClassConstructor(
customLeakDetector);
customClassConstructor =
customClassConstructor(
customLeakDetector);
}
}
private static
Constructor<?>
obsoleteCustomClassConstructor(
String customLeakDetector) {
try {
final
Class<?>
detectorClass =
Class.
forName(
customLeakDetector, true,
PlatformDependent.
getSystemClassLoader());
if (
ResourceLeakDetector.class.
isAssignableFrom(
detectorClass)) {
return
detectorClass.
getConstructor(
Class.class, int.class, long.class);
} else {
logger.
error("Class {} does not inherit from ResourceLeakDetector.",
customLeakDetector);
}
} catch (
Throwable t) {
logger.
error("Could not load custom resource leak detector class provided: {}",
customLeakDetector,
t);
}
return null;
}
private static
Constructor<?>
customClassConstructor(
String customLeakDetector) {
try {
final
Class<?>
detectorClass =
Class.
forName(
customLeakDetector, true,
PlatformDependent.
getSystemClassLoader());
if (
ResourceLeakDetector.class.
isAssignableFrom(
detectorClass)) {
return
detectorClass.
getConstructor(
Class.class, int.class);
} else {
logger.
error("Class {} does not inherit from ResourceLeakDetector.",
customLeakDetector);
}
} catch (
Throwable t) {
logger.
error("Could not load custom resource leak detector class provided: {}",
customLeakDetector,
t);
}
return null;
}
@
SuppressWarnings("deprecation")
@
Override
public <T>
ResourceLeakDetector<T>
newResourceLeakDetector(
Class<T>
resource, int
samplingInterval,
long
maxActive) {
if (
obsoleteCustomClassConstructor != null) {
try {
@
SuppressWarnings("unchecked")
ResourceLeakDetector<T>
leakDetector =
(
ResourceLeakDetector<T>)
obsoleteCustomClassConstructor.
newInstance(
resource,
samplingInterval,
maxActive);
logger.
debug("Loaded custom ResourceLeakDetector: {}",
obsoleteCustomClassConstructor.
getDeclaringClass().
getName());
return
leakDetector;
} catch (
Throwable t) {
logger.
error(
"Could not load custom resource leak detector provided: {} with the given resource: {}",
obsoleteCustomClassConstructor.
getDeclaringClass().
getName(),
resource,
t);
}
}
ResourceLeakDetector<T>
resourceLeakDetector = new
ResourceLeakDetector<T>(
resource,
samplingInterval,
maxActive);
logger.
debug("Loaded default ResourceLeakDetector: {}",
resourceLeakDetector);
return
resourceLeakDetector;
}
@
Override
public <T>
ResourceLeakDetector<T>
newResourceLeakDetector(
Class<T>
resource, int
samplingInterval) {
if (
customClassConstructor != null) {
try {
@
SuppressWarnings("unchecked")
ResourceLeakDetector<T>
leakDetector =
(
ResourceLeakDetector<T>)
customClassConstructor.
newInstance(
resource,
samplingInterval);
logger.
debug("Loaded custom ResourceLeakDetector: {}",
customClassConstructor.
getDeclaringClass().
getName());
return
leakDetector;
} catch (
Throwable t) {
logger.
error(
"Could not load custom resource leak detector provided: {} with the given resource: {}",
customClassConstructor.
getDeclaringClass().
getName(),
resource,
t);
}
}
ResourceLeakDetector<T>
resourceLeakDetector = new
ResourceLeakDetector<T>(
resource,
samplingInterval);
logger.
debug("Loaded default ResourceLeakDetector: {}",
resourceLeakDetector);
return
resourceLeakDetector;
}
}
}