1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.net;
18
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.util.HashMap;
22 import java.util.Hashtable;
23 import java.util.Map;
24
25 import org.apache.logging.log4j.Logger;
26 import org.apache.logging.log4j.core.config.plugins.Plugin;
27 import org.apache.logging.log4j.core.util.Integers;
28 import org.apache.logging.log4j.core.util.Loader;
29 import org.apache.logging.log4j.status.StatusLogger;
30
31
32
33
34
35
36
37
38 @Plugin(name = "multicastdns", category = "Core", elementType = "advertiser", printObject = false)
39 public class MulticastDnsAdvertiser implements Advertiser {
40
41
42
43 private static final int MAX_LENGTH = 255;
44
45
46
47 protected static final Logger LOGGER = StatusLogger.getLogger();
48 private static final int DEFAULT_PORT = 4555;
49
50 private static Object jmDNS = initializeJmDns();
51 private static Class<?> jmDNSClass;
52 private static Class<?> serviceInfoClass;
53
54 public MulticastDnsAdvertiser() {
55
56 }
57
58
59
60
61
62
63
64
65
66
67
68
69
70 @Override
71 public Object advertise(final Map<String, String> properties) {
72
73 final Map<String, String> truncatedProperties = new HashMap<>();
74 for (final Map.Entry<String, String> entry : properties.entrySet()) {
75 if (entry.getKey().length() <= MAX_LENGTH && entry.getValue().length() <= MAX_LENGTH) {
76 truncatedProperties.put(entry.getKey(), entry.getValue());
77 }
78 }
79 final String protocol = truncatedProperties.get("protocol");
80 final String zone = "._log4j._" + (protocol != null ? protocol : "tcp") + ".local.";
81
82 final String portString = truncatedProperties.get("port");
83 final int port = Integers.parseInt(portString, DEFAULT_PORT);
84
85 final String name = truncatedProperties.get("name");
86
87
88 if (jmDNS != null) {
89 boolean isVersion3 = false;
90 try {
91
92 jmDNSClass.getMethod("create");
93 isVersion3 = true;
94 } catch (final NoSuchMethodException e) {
95
96 }
97 Object serviceInfo;
98 if (isVersion3) {
99 serviceInfo = buildServiceInfoVersion3(zone, port, name, truncatedProperties);
100 } else {
101 serviceInfo = buildServiceInfoVersion1(zone, port, name, truncatedProperties);
102 }
103
104 try {
105 final Method method = jmDNSClass.getMethod("registerService", serviceInfoClass);
106 method.invoke(jmDNS, serviceInfo);
107 } catch (final IllegalAccessException e) {
108 LOGGER.warn("Unable to invoke registerService method", e);
109 } catch (final NoSuchMethodException e) {
110 LOGGER.warn("No registerService method", e);
111 } catch (final InvocationTargetException e) {
112 LOGGER.warn("Unable to invoke registerService method", e);
113 }
114 return serviceInfo;
115 }
116 LOGGER.warn("JMDNS not available - will not advertise ZeroConf support");
117 return null;
118 }
119
120
121
122
123
124
125 @Override
126 public void unadvertise(final Object serviceInfo) {
127 if (jmDNS != null) {
128 try {
129 final Method method = jmDNSClass.getMethod("unregisterService", serviceInfoClass);
130 method.invoke(jmDNS, serviceInfo);
131 } catch (final IllegalAccessException e) {
132 LOGGER.warn("Unable to invoke unregisterService method", e);
133 } catch (final NoSuchMethodException e) {
134 LOGGER.warn("No unregisterService method", e);
135 } catch (final InvocationTargetException e) {
136 LOGGER.warn("Unable to invoke unregisterService method", e);
137 }
138 }
139 }
140
141 private static Object createJmDnsVersion1() {
142 try {
143 return jmDNSClass.getConstructor().newInstance();
144 } catch (final InstantiationException e) {
145 LOGGER.warn("Unable to instantiate JMDNS", e);
146 } catch (final IllegalAccessException e) {
147 LOGGER.warn("Unable to instantiate JMDNS", e);
148 } catch (final NoSuchMethodException e) {
149 LOGGER.warn("Unable to instantiate JMDNS", e);
150 } catch (final InvocationTargetException e) {
151 LOGGER.warn("Unable to instantiate JMDNS", e);
152 }
153 return null;
154 }
155
156 private static Object createJmDnsVersion3() {
157 try {
158 final Method jmDNSCreateMethod = jmDNSClass.getMethod("create");
159 return jmDNSCreateMethod.invoke(null, (Object[]) null);
160 } catch (final IllegalAccessException e) {
161 LOGGER.warn("Unable to invoke create method", e);
162 } catch (final NoSuchMethodException e) {
163 LOGGER.warn("Unable to get create method", e);
164 } catch (final InvocationTargetException e) {
165 LOGGER.warn("Unable to invoke create method", e);
166 }
167 return null;
168 }
169
170 private static Object buildServiceInfoVersion1(final String zone, final int port, final String name,
171 final Map<String, String> properties) {
172
173 @SuppressWarnings("UseOfObsoleteCollectionType")
174 final Hashtable<String, String> hashtableProperties = new Hashtable<>(properties);
175 try {
176 return serviceInfoClass.getConstructor(String.class, String.class, int.class, int.class, int.class,
177 Hashtable.class).newInstance(zone, name, port, 0, 0, hashtableProperties);
178 } catch (final IllegalAccessException e) {
179 LOGGER.warn("Unable to construct ServiceInfo instance", e);
180 } catch (final NoSuchMethodException e) {
181 LOGGER.warn("Unable to get ServiceInfo constructor", e);
182 } catch (final InstantiationException e) {
183 LOGGER.warn("Unable to construct ServiceInfo instance", e);
184 } catch (final InvocationTargetException e) {
185 LOGGER.warn("Unable to construct ServiceInfo instance", e);
186 }
187 return null;
188 }
189
190 private static Object buildServiceInfoVersion3(final String zone, final int port, final String name,
191 final Map<String, String> properties) {
192 try {
193 return serviceInfoClass
194
195 .getMethod("create", String.class, String.class, int.class, int.class, int.class, Map.class)
196 .invoke(null, zone, name, port, 0, 0, properties);
197 } catch (final IllegalAccessException e) {
198 LOGGER.warn("Unable to invoke create method", e);
199 } catch (final NoSuchMethodException e) {
200 LOGGER.warn("Unable to find create method", e);
201 } catch (final InvocationTargetException e) {
202 LOGGER.warn("Unable to invoke create method", e);
203 }
204 return null;
205 }
206
207 private static Object initializeJmDns() {
208 try {
209 jmDNSClass = Loader.loadClass("javax.jmdns.JmDNS");
210 serviceInfoClass = Loader.loadClass("javax.jmdns.ServiceInfo");
211
212 boolean isVersion3 = false;
213 try {
214
215 jmDNSClass.getMethod("create");
216 isVersion3 = true;
217 } catch (final NoSuchMethodException e) {
218
219 }
220
221 if (isVersion3) {
222 return createJmDnsVersion3();
223 }
224 return createJmDnsVersion1();
225 } catch (final ClassNotFoundException e) {
226 LOGGER.warn("JmDNS or serviceInfo class not found", e);
227 } catch (final ExceptionInInitializerError e2) {
228 LOGGER.warn("JmDNS or serviceInfo class not found", e2);
229 }
230 return null;
231 }
232 }