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 | InvocationTargetException e) {
106 LOGGER.warn("Unable to invoke registerService method", e);
107 } catch (final NoSuchMethodException e) {
108 LOGGER.warn("No registerService method", e);
109 }
110 return serviceInfo;
111 }
112 LOGGER.warn("JMDNS not available - will not advertise ZeroConf support");
113 return null;
114 }
115
116
117
118
119
120
121 @Override
122 public void unadvertise(final Object serviceInfo) {
123 if (jmDNS != null) {
124 try {
125 final Method method = jmDNSClass.getMethod("unregisterService", serviceInfoClass);
126 method.invoke(jmDNS, serviceInfo);
127 } catch (final IllegalAccessException | InvocationTargetException e) {
128 LOGGER.warn("Unable to invoke unregisterService method", e);
129 } catch (final NoSuchMethodException e) {
130 LOGGER.warn("No unregisterService method", e);
131 }
132 }
133 }
134
135 private static Object createJmDnsVersion1() {
136 try {
137 return jmDNSClass.getConstructor().newInstance();
138 } catch (final InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
139 LOGGER.warn("Unable to instantiate JMDNS", e);
140 }
141 return null;
142 }
143
144 private static Object createJmDnsVersion3() {
145 try {
146 final Method jmDNSCreateMethod = jmDNSClass.getMethod("create");
147 return jmDNSCreateMethod.invoke(null, (Object[]) null);
148 } catch (final IllegalAccessException | InvocationTargetException e) {
149 LOGGER.warn("Unable to invoke create method", e);
150 } catch (final NoSuchMethodException e) {
151 LOGGER.warn("Unable to get create method", e);
152 }
153 return null;
154 }
155
156 private static Object buildServiceInfoVersion1(final String zone, final int port, final String name,
157 final Map<String, String> properties) {
158
159 @SuppressWarnings("UseOfObsoleteCollectionType")
160 final Hashtable<String, String> hashtableProperties = new Hashtable<>(properties);
161 try {
162 return serviceInfoClass.getConstructor(String.class, String.class, int.class, int.class, int.class,
163 Hashtable.class).newInstance(zone, name, port, 0, 0, hashtableProperties);
164 } catch (final IllegalAccessException | InstantiationException | InvocationTargetException e) {
165 LOGGER.warn("Unable to construct ServiceInfo instance", e);
166 } catch (final NoSuchMethodException e) {
167 LOGGER.warn("Unable to get ServiceInfo constructor", e);
168 }
169 return null;
170 }
171
172 private static Object buildServiceInfoVersion3(final String zone, final int port, final String name,
173 final Map<String, String> properties) {
174 try {
175 return serviceInfoClass
176
177 .getMethod("create", String.class, String.class, int.class, int.class, int.class, Map.class)
178 .invoke(null, zone, name, port, 0, 0, properties);
179 } catch (final IllegalAccessException | InvocationTargetException e) {
180 LOGGER.warn("Unable to invoke create method", e);
181 } catch (final NoSuchMethodException e) {
182 LOGGER.warn("Unable to find create method", e);
183 }
184 return null;
185 }
186
187 private static Object initializeJmDns() {
188 try {
189 jmDNSClass = Loader.loadClass("javax.jmdns.JmDNS");
190 serviceInfoClass = Loader.loadClass("javax.jmdns.ServiceInfo");
191
192 boolean isVersion3 = false;
193 try {
194
195 jmDNSClass.getMethod("create");
196 isVersion3 = true;
197 } catch (final NoSuchMethodException e) {
198
199 }
200
201 if (isVersion3) {
202 return createJmDnsVersion3();
203 }
204 return createJmDnsVersion1();
205 } catch (final ClassNotFoundException | ExceptionInInitializerError e) {
206 LOGGER.warn("JmDNS or serviceInfo class not found", e);
207 }
208 return null;
209 }
210 }