1 /***
2 *
3 * Copyright 2004 Protique Ltd
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 **/
18 package org.codehaus.activemq.transport.zeroconf;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.codehaus.activemq.ConfigurationException;
23 import org.codehaus.activemq.NotStartedException;
24 import org.codehaus.activemq.transport.DiscoveryAgent;
25 import org.codehaus.activemq.transport.DiscoveryAgentSupport;
26 import org.codehaus.activemq.transport.DiscoveryEvent;
27 import org.codehaus.activemq.util.JMSExceptionHelper;
28 import org.codehaus.activemq.util.MapHelper;
29
30 import javax.jmdns.JmDNS;
31 import javax.jmdns.ServiceInfo;
32 import javax.jmdns.ServiceListener;
33 import javax.jms.JMSException;
34 import java.io.IOException;
35 import java.net.InetAddress;
36 import java.net.UnknownHostException;
37 import java.util.Enumeration;
38 import java.util.HashMap;
39 import java.util.Hashtable;
40 import java.util.Map;
41
42 /***
43 * A {@link DiscoveryAgent} using <a href="http://www.zeroconf.org/">Zeroconf</a>
44 * via the <a href="http://jmdns.sf.net/">jmDNS</a> library
45 *
46 * @version $Revision: 1.5 $
47 */
48 public class ZeroconfDiscoveryAgent extends DiscoveryAgentSupport implements ServiceListener {
49 private static final Log log = LogFactory.getLog(ZeroconfDiscoveryAgent.class);
50
51 private JmDNS jmdns;
52 private InetAddress localAddress;
53 private String localhost;
54 private String type;
55 private int weight = 0;
56 private int priority = 0;
57
58
59
60 public void start() throws JMSException {
61 if (type == null) {
62 throw new ConfigurationException("You must specify a type of service to discover");
63 }
64 if (!type.endsWith(".")) {
65 log.warn("The type '" + type + "' should end with '.' to be a valid Zeroconf type");
66 type += ".";
67 }
68 try {
69 if (jmdns == null) {
70 jmdns = createJmDNS();
71 }
72 if (getDiscoveryListener() != null) {
73 log.info("Discovering service of type: " + type);
74 jmdns.addServiceListener(type, this);
75 }
76 }
77 catch (IOException e) {
78 JMSExceptionHelper.newJMSException("Failed to start JmDNS service: " + e, e);
79 }
80 }
81
82 public void stop() throws JMSException {
83 jmdns.unregisterAllServices();
84 jmdns.close();
85 }
86
87 public void registerService(String name, Map details) throws JMSException {
88 if (jmdns == null) {
89 throw new NotStartedException();
90 }
91 try {
92 jmdns.registerService(createServiceInfo(name, details));
93 }
94 catch (IOException e) {
95 JMSExceptionHelper.newJMSException("Could not register service: " + name + ". Reason: " + e, e);
96 }
97 }
98
99
100
101
102 public void addService(JmDNS jmDNS, String type, String name) {
103 if (log.isDebugEnabled()) {
104 log.debug("addService with type: " + type + " name: " + name);
105 }
106 jmDNS.requestServiceInfo(type, name);
107 }
108
109 public void removeService(JmDNS jmDNS, String type, String name) {
110 if (log.isDebugEnabled()) {
111 log.debug("removeService with type: " + type + " name: " + name);
112 }
113 DiscoveryEvent event = new DiscoveryEvent(this, name);
114 getDiscoveryListener().removeService(event);
115 }
116
117 public void resolveService(JmDNS jmDNS, String type, String name, ServiceInfo serviceInfo) {
118 if (log.isDebugEnabled()) {
119 log.debug("removeService with type: " + type + " name: " + name + " info: " + serviceInfo);
120 }
121
122 Map map = new HashMap();
123 if (serviceInfo != null) {
124 Enumeration iter = serviceInfo.getPropertyNames();
125 while (iter.hasMoreElements()) {
126 String key = (String) iter.nextElement();
127 String value = serviceInfo.getPropertyString(key);
128 map.put(key, value);
129 }
130 }
131 DiscoveryEvent event = new DiscoveryEvent(this, name, map);
132 getDiscoveryListener().addService(event);
133 }
134
135 public String getType() {
136 return type;
137 }
138
139 public void setType(String type) {
140 this.type = type;
141 }
142
143 public int getPriority() {
144 return priority;
145 }
146
147 public void setPriority(int priority) {
148 this.priority = priority;
149 }
150
151 public int getWeight() {
152 return weight;
153 }
154
155 public void setWeight(int weight) {
156 this.weight = weight;
157 }
158
159 public JmDNS getJmdns() {
160 return jmdns;
161 }
162
163 public void setJmdns(JmDNS jmdns) {
164 this.jmdns = jmdns;
165 }
166
167
168 public InetAddress getLocalAddress() throws UnknownHostException {
169 if (localAddress == null) {
170 localAddress = createLocalAddress();
171 }
172 return localAddress;
173 }
174
175 public void setLocalAddress(InetAddress localAddress) {
176 this.localAddress = localAddress;
177 }
178
179 public String getLocalhost() {
180 return localhost;
181 }
182
183 public void setLocalhost(String localhost) {
184 this.localhost = localhost;
185 }
186
187
188
189 protected ServiceInfo createServiceInfo(String name, Map map) {
190 name += "." + type;
191 int port = MapHelper.getInt(map, "port", 0);
192
193 if (log.isDebugEnabled()) {
194 log.debug("Registering service type: " + type + " name: " + name + " details: " + map);
195 }
196 return new ServiceInfo(type, name, port, weight, priority, new Hashtable(map));
197 }
198
199 protected JmDNS createJmDNS() throws IOException {
200 return new JmDNS(getLocalAddress());
201 }
202
203 protected InetAddress createLocalAddress() throws UnknownHostException {
204 if (localhost != null) {
205 return InetAddress.getByName(localhost);
206 }
207 return InetAddress.getLocalHost();
208 }
209 }