1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty5.util;
18
19 import io.netty5.util.internal.ObjectUtil;
20 import io.netty5.util.internal.PlatformDependent;
21 import io.netty5.util.internal.SystemPropertyUtil;
22 import io.netty5.util.internal.logging.InternalLogger;
23 import io.netty5.util.internal.logging.InternalLoggerFactory;
24
25 import java.lang.reflect.Constructor;
26
27 import static java.util.Objects.requireNonNull;
28
29
30
31
32 public abstract class ResourceLeakDetectorFactory {
33 private static final InternalLogger logger = InternalLoggerFactory.getInstance(ResourceLeakDetectorFactory.class);
34
35 private static volatile ResourceLeakDetectorFactory factoryInstance = new DefaultResourceLeakDetectorFactory();
36
37
38
39
40
41
42 public static ResourceLeakDetectorFactory instance() {
43 return factoryInstance;
44 }
45
46
47
48
49
50
51
52
53 public static void setResourceLeakDetectorFactory(ResourceLeakDetectorFactory factory) {
54 factoryInstance = requireNonNull(factory, "factory");
55 }
56
57
58
59
60
61
62
63
64 public final <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource) {
65 return newResourceLeakDetector(resource, ResourceLeakDetector.SAMPLING_INTERVAL);
66 }
67
68
69
70
71
72
73
74
75
76 public abstract <T> ResourceLeakDetector<T> newResourceLeakDetector(
77 Class<T> resource, int samplingInterval);
78
79
80
81
82 private static final class DefaultResourceLeakDetectorFactory extends ResourceLeakDetectorFactory {
83 private final Constructor<?> customClassConstructor;
84
85 DefaultResourceLeakDetectorFactory() {
86 String customLeakDetector;
87 try {
88 customLeakDetector = SystemPropertyUtil.get("io.netty5.customResourceLeakDetector");
89 } catch (Throwable cause) {
90 logger.error("Could not access System property: io.netty5.customResourceLeakDetector", cause);
91 customLeakDetector = null;
92 }
93 if (customLeakDetector == null) {
94 customClassConstructor = null;
95 } else {
96 customClassConstructor = customClassConstructor(customLeakDetector);
97 }
98 }
99
100 private static Constructor<?> customClassConstructor(String customLeakDetector) {
101 try {
102 final Class<?> detectorClass = Class.forName(customLeakDetector, true,
103 PlatformDependent.getSystemClassLoader());
104
105 if (ResourceLeakDetector.class.isAssignableFrom(detectorClass)) {
106 return detectorClass.getConstructor(Class.class, int.class);
107 } else {
108 logger.error("Class {} does not inherit from ResourceLeakDetector.", customLeakDetector);
109 }
110 } catch (Throwable t) {
111 logger.error("Could not load custom resource leak detector class provided: {}",
112 customLeakDetector, t);
113 }
114 return null;
115 }
116
117 @Override
118 public <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource, int samplingInterval) {
119 ObjectUtil.checkPositive(samplingInterval, "samplingInterval");
120 if (customClassConstructor != null) {
121 try {
122 @SuppressWarnings("unchecked")
123 ResourceLeakDetector<T> leakDetector =
124 (ResourceLeakDetector<T>) customClassConstructor.newInstance(resource, samplingInterval);
125 logger.debug("Loaded custom ResourceLeakDetector: {}",
126 customClassConstructor.getDeclaringClass().getName());
127 return leakDetector;
128 } catch (Throwable t) {
129 logger.error(
130 "Could not load custom resource leak detector provided: {} with the given resource: {}",
131 customClassConstructor.getDeclaringClass().getName(), resource, t);
132 }
133 }
134
135 ResourceLeakDetector<T> resourceLeakDetector = new ResourceLeakDetector<>(resource, samplingInterval);
136 logger.debug("Loaded default ResourceLeakDetector: {}", resourceLeakDetector);
137 return resourceLeakDetector;
138 }
139 }
140 }