1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.config.plugins.convert;
18
19 import java.lang.reflect.ParameterizedType;
20 import java.lang.reflect.Type;
21 import java.util.Collection;
22 import java.util.Map;
23 import java.util.Objects;
24 import java.util.UnknownFormatConversionException;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27
28 import org.apache.logging.log4j.Logger;
29 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
30 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
31 import org.apache.logging.log4j.core.util.ReflectionUtil;
32 import org.apache.logging.log4j.core.util.TypeUtil;
33 import org.apache.logging.log4j.status.StatusLogger;
34
35
36
37
38
39
40 public class TypeConverterRegistry {
41
42 private static final Logger LOGGER = StatusLogger.getLogger();
43 private static volatile TypeConverterRegistry INSTANCE;
44 private static final Object INSTANCE_LOCK = new Object();
45
46 private final ConcurrentMap<Type, TypeConverter<?>> registry = new ConcurrentHashMap<>();
47
48
49
50
51
52
53 public static TypeConverterRegistry getInstance() {
54 TypeConverterRegistry result = INSTANCE;
55 if (result == null) {
56 synchronized (INSTANCE_LOCK) {
57 result = INSTANCE;
58 if (result == null) {
59 INSTANCE = result = new TypeConverterRegistry();
60 }
61 }
62 }
63 return result;
64 }
65
66
67
68
69
70
71
72
73
74
75
76 public TypeConverter<?> findCompatibleConverter(final Type type) {
77 Objects.requireNonNull(type, "No type was provided");
78 final TypeConverter<?> primary = registry.get(type);
79
80 if (primary != null) {
81 return primary;
82 }
83
84 if (type instanceof Class<?>) {
85 final Class<?> clazz = (Class<?>) type;
86 if (clazz.isEnum()) {
87 @SuppressWarnings({"unchecked","rawtypes"})
88 final EnumConverter<? extends Enum> converter = new EnumConverter(clazz.asSubclass(Enum.class));
89 registry.putIfAbsent(type, converter);
90 return converter;
91 }
92 }
93
94 for (final Map.Entry<Type, TypeConverter<?>> entry : registry.entrySet()) {
95 final Type key = entry.getKey();
96 if (TypeUtil.isAssignable(type, key)) {
97 LOGGER.debug("Found compatible TypeConverter<{}> for type [{}].", key, type);
98 final TypeConverter<?> value = entry.getValue();
99 registry.putIfAbsent(type, value);
100 return value;
101 }
102 }
103 throw new UnknownFormatConversionException(type.toString());
104 }
105
106 private TypeConverterRegistry() {
107 LOGGER.trace("TypeConverterRegistry initializing.");
108 final PluginManager manager = new PluginManager(TypeConverters.CATEGORY);
109 manager.collectPlugins();
110 loadKnownTypeConverters(manager.getPlugins().values());
111 registerPrimitiveTypes();
112 }
113
114 private void loadKnownTypeConverters(final Collection<PluginType<?>> knownTypes) {
115 for (final PluginType<?> knownType : knownTypes) {
116 final Class<?> clazz = knownType.getPluginClass();
117 if (TypeConverter.class.isAssignableFrom(clazz)) {
118 @SuppressWarnings("rawtypes")
119 final Class<? extends TypeConverter> pluginClass = clazz.asSubclass(TypeConverter.class);
120 final Type conversionType = getTypeConverterSupportedType(pluginClass);
121 final TypeConverter<?> converter = ReflectionUtil.instantiate(pluginClass);
122 if (registry.putIfAbsent(conversionType, converter) != null) {
123 LOGGER.warn("Found a TypeConverter [{}] for type [{}] that already exists.", converter,
124 conversionType);
125 }
126 }
127 }
128 }
129
130 private static Type getTypeConverterSupportedType(@SuppressWarnings("rawtypes") final Class<? extends TypeConverter> typeConverterClass) {
131 for (final Type type : typeConverterClass.getGenericInterfaces()) {
132 if (type instanceof ParameterizedType) {
133 final ParameterizedType pType = (ParameterizedType) type;
134 if (TypeConverter.class.equals(pType.getRawType())) {
135
136 return pType.getActualTypeArguments()[0];
137 }
138 }
139 }
140 return Void.TYPE;
141 }
142
143 private void registerPrimitiveTypes() {
144 registerTypeAlias(Boolean.class, Boolean.TYPE);
145 registerTypeAlias(Byte.class, Byte.TYPE);
146 registerTypeAlias(Character.class, Character.TYPE);
147 registerTypeAlias(Double.class, Double.TYPE);
148 registerTypeAlias(Float.class, Float.TYPE);
149 registerTypeAlias(Integer.class, Integer.TYPE);
150 registerTypeAlias(Long.class, Long.TYPE);
151 registerTypeAlias(Short.class, Short.TYPE);
152 }
153
154 private void registerTypeAlias(final Type knownType, final Type aliasType) {
155 registry.putIfAbsent(aliasType, registry.get(knownType));
156 }
157
158 }