/**
*
* Copyright 2004 Protique Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**/
package org.codehaus.activemq.transport.zeroconf;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.ConfigurationException;
import org.codehaus.activemq.NotStartedException;
import org.codehaus.activemq.transport.DiscoveryAgent;
import org.codehaus.activemq.transport.DiscoveryAgentSupport;
import org.codehaus.activemq.transport.DiscoveryEvent;
import org.codehaus.activemq.util.JMSExceptionHelper;
import org.codehaus.activemq.util.MapHelper;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import javax.jms.JMSException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
/**
* A {@link DiscoveryAgent} using <a href="http://www.zeroconf.org/">Zeroconf</a>
* via the <a href="http://jmdns.sf.net/">jmDNS</a> library
*
* @version $Revision: 1.5 $
*/
public class ZeroconfDiscoveryAgent extends DiscoveryAgentSupport implements ServiceListener {
private static final Log log = LogFactory.getLog(ZeroconfDiscoveryAgent.class);
private JmDNS jmdns;
private InetAddress localAddress;
private String localhost;
private String type;
private int weight = 0;
private int priority = 0;
// DiscoveryAgent interface
//-------------------------------------------------------------------------
public void start() throws JMSException {
if (type == null) {
throw new ConfigurationException("You must specify a type of service to discover");
}
if (!type.endsWith(".")) {
log.warn("The type '" + type + "' should end with '.' to be a valid Zeroconf type");
type += ".";
}
try {
if (jmdns == null) {
jmdns = createJmDNS();
}
if (getDiscoveryListener() != null) {
log.info("Discovering service of type: " + type);
jmdns.addServiceListener(type, this);
}
}
catch (IOException e) {
JMSExceptionHelper.newJMSException("Failed to start JmDNS service: " + e, e);
}
}
public void stop() throws JMSException {
jmdns.unregisterAllServices();
jmdns.close();
}
public void registerService(String name, Map details) throws JMSException {
if (jmdns == null) {
throw new NotStartedException();
}
try {
jmdns.registerService(createServiceInfo(name, details));
}
catch (IOException e) {
JMSExceptionHelper.newJMSException("Could not register service: " + name + ". Reason: " + e, e);
}
}
// ServiceListener interface
//-------------------------------------------------------------------------
public void addService(JmDNS jmDNS, String type, String name) {
if (log.isDebugEnabled()) {
log.debug("addService with type: " + type + " name: " + name);
}
jmDNS.requestServiceInfo(type, name);
}
public void removeService(JmDNS jmDNS, String type, String name) {
if (log.isDebugEnabled()) {
log.debug("removeService with type: " + type + " name: " + name);
}
DiscoveryEvent event = new DiscoveryEvent(this, name);
getDiscoveryListener().removeService(event);
}
public void resolveService(JmDNS jmDNS, String type, String name, ServiceInfo serviceInfo) {
if (log.isDebugEnabled()) {
log.debug("removeService with type: " + type + " name: " + name + " info: " + serviceInfo);
}
Map map = new HashMap();
if (serviceInfo != null) {
Enumeration iter = serviceInfo.getPropertyNames();
while (iter.hasMoreElements()) {
String key = (String) iter.nextElement();
String value = serviceInfo.getPropertyString(key);
map.put(key, value);
}
}
DiscoveryEvent event = new DiscoveryEvent(this, name, map);
getDiscoveryListener().addService(event);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public JmDNS getJmdns() {
return jmdns;
}
public void setJmdns(JmDNS jmdns) {
this.jmdns = jmdns;
}
public InetAddress getLocalAddress() throws UnknownHostException {
if (localAddress == null) {
localAddress = createLocalAddress();
}
return localAddress;
}
public void setLocalAddress(InetAddress localAddress) {
this.localAddress = localAddress;
}
public String getLocalhost() {
return localhost;
}
public void setLocalhost(String localhost) {
this.localhost = localhost;
}
// Implementation methods
//-------------------------------------------------------------------------
protected ServiceInfo createServiceInfo(String name, Map map) {
name += "." + type;
int port = MapHelper.getInt(map, "port", 0);
if (log.isDebugEnabled()) {
log.debug("Registering service type: " + type + " name: " + name + " details: " + map);
}
return new ServiceInfo(type, name, port, weight, priority, new Hashtable(map));
}
protected JmDNS createJmDNS() throws IOException {
return new JmDNS(getLocalAddress());
}
protected InetAddress createLocalAddress() throws UnknownHostException {
if (localhost != null) {
return InetAddress.getByName(localhost);
}
return InetAddress.getLocalHost();
}
}