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.Constructor;
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.util.HashMap;
23 import java.util.Hashtable;
24 import java.util.Map;
25
26 import org.apache.logging.log4j.Logger;
27 import org.apache.logging.log4j.core.config.plugins.Plugin;
28 import org.apache.logging.log4j.core.helpers.Integers;
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 protected static final Logger LOGGER = StatusLogger.getLogger();
41 private static Object jmDNS = initializeJMDNS();
42
43 private static Class<?> jmDNSClass;
44 private static Class<?> serviceInfoClass;
45
46 public MulticastDNSAdvertiser()
47 {
48
49 }
50
51
52
53
54
55
56
57
58
59
60
61
62
63 @Override
64 public Object advertise(final Map<String, String> properties) {
65
66 final Map<String, String> truncatedProperties = new HashMap<String, String>();
67 for (final Map.Entry<String, String> entry:properties.entrySet())
68 {
69 if (entry.getKey().length() <= 255 && entry.getValue().length() <= 255)
70 {
71 truncatedProperties.put(entry.getKey(), entry.getValue());
72 }
73 }
74 final String protocol = truncatedProperties.get("protocol");
75 final String zone = "._log4j._"+(protocol != null ? protocol : "tcp") + ".local.";
76
77 final String portString = truncatedProperties.get("port");
78 final int port = Integers.parseInt(portString, 4555);
79
80 final String name = truncatedProperties.get("name");
81
82
83 if (jmDNS != null)
84 {
85 boolean isVersion3 = false;
86 try {
87
88 jmDNSClass.getMethod("create", (Class[])null);
89 isVersion3 = true;
90 } catch (final NoSuchMethodException e) {
91
92 }
93 Object serviceInfo;
94 if (isVersion3) {
95 serviceInfo = buildServiceInfoVersion3(zone, port, name, truncatedProperties);
96 } else {
97 serviceInfo = buildServiceInfoVersion1(zone, port, name, truncatedProperties);
98 }
99
100 try {
101 final Method method = jmDNSClass.getMethod("registerService", new Class[]{serviceInfoClass});
102 method.invoke(jmDNS, serviceInfo);
103 } catch(final IllegalAccessException e) {
104 LOGGER.warn("Unable to invoke registerService method", e);
105 } catch(final NoSuchMethodException e) {
106 LOGGER.warn("No registerService method", e);
107 } catch(final InvocationTargetException e) {
108 LOGGER.warn("Unable to invoke registerService method", e);
109 }
110 return serviceInfo;
111 }
112 else
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", new Class[]{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 {
141 try {
142 return jmDNSClass.newInstance();
143 } catch (final InstantiationException e) {
144 LOGGER.warn("Unable to instantiate JMDNS", e);
145 } catch (final IllegalAccessException e) {
146 LOGGER.warn("Unable to instantiate JMDNS", e);
147 }
148 return null;
149 }
150
151 private static Object createJmDNSVersion3()
152 {
153 try {
154 final Method jmDNSCreateMethod = jmDNSClass.getMethod("create", (Class[])null);
155 return jmDNSCreateMethod.invoke(null, (Object[])null);
156 } catch (final IllegalAccessException e) {
157 LOGGER.warn("Unable to instantiate jmdns class", e);
158 } catch (final NoSuchMethodException e) {
159 LOGGER.warn("Unable to access constructor", e);
160 } catch (final InvocationTargetException e) {
161 LOGGER.warn("Unable to call constructor", e);
162 }
163 return null;
164 }
165
166 private Object buildServiceInfoVersion1(final String zone, final int port, final String name, final Map<String, String> properties) {
167
168 final Hashtable<String, String> hashtableProperties = new Hashtable<String, String>(properties);
169 try {
170 final Class<?>[] args = new Class<?>[6];
171 args[0] = String.class;
172 args[1] = String.class;
173 args[2] = int.class;
174 args[3] = int.class;
175 args[4] = int.class;
176 args[5] = Hashtable.class;
177 final Constructor<?> constructor = serviceInfoClass.getConstructor(args);
178 final Object[] values = new Object[6];
179 values[0] = zone;
180 values[1] = name;
181 values[2] = port;
182 values[3] = 0;
183 values[4] = 0;
184 values[5] = hashtableProperties;
185 return constructor.newInstance(values);
186 } catch (final IllegalAccessException e) {
187 LOGGER.warn("Unable to construct ServiceInfo instance", e);
188 } catch (final NoSuchMethodException e) {
189 LOGGER.warn("Unable to get ServiceInfo constructor", e);
190 } catch (final InstantiationException e) {
191 LOGGER.warn("Unable to construct ServiceInfo instance", e);
192 } catch (final InvocationTargetException e) {
193 LOGGER.warn("Unable to construct ServiceInfo instance", e);
194 }
195 return null;
196 }
197
198 private Object buildServiceInfoVersion3(final String zone, final int port, final String name, final Map<String, String> properties) {
199 try {
200 final Class<?>[] args = new Class<?>[6];
201 args[0] = String.class;
202 args[1] = String.class;
203 args[2] = int.class;
204 args[3] = int.class;
205 args[4] = int.class;
206 args[5] = Map.class;
207 final Method serviceInfoCreateMethod = serviceInfoClass.getMethod("create", args);
208 final Object[] values = new Object[6];
209 values[0] = zone;
210 values[1] = name;
211 values[2] = port;
212 values[3] = 0;
213 values[4] = 0;
214 values[5] = properties;
215 return serviceInfoCreateMethod.invoke(null, values);
216 } catch (final IllegalAccessException e) {
217 LOGGER.warn("Unable to invoke create method", e);
218 } catch (final NoSuchMethodException e) {
219 LOGGER.warn("Unable to find create method", e);
220 } catch (final InvocationTargetException e) {
221 LOGGER.warn("Unable to invoke create method", e);
222 }
223 return null;
224 }
225
226 private static Object initializeJMDNS() {
227 try {
228 jmDNSClass = Class.forName("javax.jmdns.JmDNS");
229 serviceInfoClass = Class.forName("javax.jmdns.ServiceInfo");
230
231 boolean isVersion3 = false;
232 try {
233
234 jmDNSClass.getMethod("create", (Class[])null);
235 isVersion3 = true;
236 } catch (final NoSuchMethodException e) {
237
238 }
239
240 if (isVersion3) {
241 return createJmDNSVersion3();
242 } else {
243 return createJmDNSVersion1();
244 }
245 } catch (final ClassNotFoundException e) {
246 LOGGER.warn("JmDNS or serviceInfo class not found", e);
247 } catch (final ExceptionInInitializerError e2) {
248 LOGGER.warn("JmDNS or serviceInfo class not found", e2);
249 }
250 return null;
251 }
252 }