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