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