/****************************************************************************
* Copyright (c) 2004 Composent, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Composent, Inc. - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.provider.jmdns.container;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import javax.jmdns.ServiceTypeListener;
import org.eclipse.core.runtime.IAdapterManager;
import org.eclipse.ecf.core.ContainerConnectException;
import org.eclipse.ecf.core.IContainer;
import org.eclipse.ecf.core.IContainerListener;
import org.eclipse.ecf.core.events.ContainerConnectedEvent;
import org.eclipse.ecf.core.events.ContainerConnectingEvent;
import org.eclipse.ecf.core.events.ContainerDisconnectedEvent;
import org.eclipse.ecf.core.events.ContainerDisconnectingEvent;
import org.eclipse.ecf.core.events.ContainerDisposeEvent;
import org.eclipse.ecf.core.events.IContainerEvent;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.identity.IDCreateException;
import org.eclipse.ecf.core.identity.IDFactory;
import org.eclipse.ecf.core.identity.Namespace;
import org.eclipse.ecf.core.security.IConnectContext;
import org.eclipse.ecf.core.util.ECFException;
import org.eclipse.ecf.core.util.Trace;
import org.eclipse.ecf.discovery.IServiceInfo;
import org.eclipse.ecf.discovery.IServiceListener;
import org.eclipse.ecf.discovery.IServiceProperties;
import org.eclipse.ecf.discovery.IServiceTypeListener;
import org.eclipse.ecf.discovery.ServiceContainerEvent;
import org.eclipse.ecf.discovery.ServiceProperties;
import org.eclipse.ecf.discovery.identity.IServiceID;
import org.eclipse.ecf.discovery.identity.ServiceID;
import org.eclipse.ecf.discovery.service.IDiscoveryService;
import org.eclipse.ecf.internal.provider.jmdns.JMDNSDebugOptions;
import org.eclipse.ecf.internal.provider.jmdns.JMDNSPlugin;
import org.eclipse.ecf.internal.provider.jmdns.Messages;
import org.eclipse.ecf.provider.jmdns.identity.JMDNSServiceID;
public class JMDNSDiscoveryContainer implements IContainer,
IDiscoveryService, ServiceListener, ServiceTypeListener {
public static final int DEFAULT_REQUEST_TIMEOUT = 3000;
protected static String JMDNS_NAMESPACE_ID = Messages
.getString("JMDNSPlugin.namespace.identifier"); //$NON-NLS-1$;
ContainerConfig config = null;
InetAddress intf = null;
JmDNS jmdns = null;
int requestTimeout = DEFAULT_REQUEST_TIMEOUT;
Map serviceListeners = new HashMap();
Vector serviceTypeListeners = new Vector();
private Vector listeners = new Vector();
public JMDNSDiscoveryContainer() throws IOException, IDCreateException {
this(null);
}
public ID getID() {
if (config == null)
return null;
else
return config.getID();
}
public JMDNSDiscoveryContainer(InetAddress addr) throws IOException,
IDCreateException {
super();
intf = (addr == null) ? InetAddress.getLocalHost() : addr;
this.config = new ContainerConfig(IDFactory.getDefault()
.createStringID(JMDNSDiscoveryContainer.class.getName()));
}
/* (non-Javadoc)
* @see org.eclipse.ecf.discovery.IDiscoveryContainerAdapter#addServiceListener(java.lang.String, org.eclipse.ecf.discovery.IServiceListener)
*/
public void addServiceListener(String type, IServiceListener listener) {
if (type == null || listener == null)
return;
synchronized (serviceListeners) {
Vector v = (Vector) serviceListeners.get(type);
if (v == null) {
v = new Vector();
serviceListeners.put(type, v);
}
v.add(listener);
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.discovery.IDiscoveryContainerAdapter#addServiceTypeListener(org.eclipse.ecf.discovery.IServiceTypeListener)
*/
public void addServiceTypeListener(IServiceTypeListener listener) {
serviceTypeListeners.add(listener);
}
protected void fireContainerEvent(IContainerEvent event) {
synchronized (listeners) {
for (Iterator i = listeners.iterator(); i.hasNext();) {
IContainerListener l = (IContainerListener) i.next();
l.handleEvent(event);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.core.IContainer#dispose()
*/
public void dispose() {
disconnect();
fireContainerEvent(new ContainerDisposeEvent(getID()));
}
protected void fireServiceAdded(ServiceEvent arg0) {
IServiceInfo iinfo = createIServiceInfoFromServiceEvent(arg0);
synchronized (serviceListeners) {
Vector v = (Vector) serviceListeners.get(arg0.getType());
if (v != null) {
for (Iterator i = v.iterator(); i.hasNext();) {
IServiceListener l = (IServiceListener) i.next();
l.serviceAdded(new ServiceContainerEvent(iinfo, config
.getID()));
}
}
}
}
protected void fireServiceRemoved(ServiceEvent arg0) {
IServiceInfo iinfo = createIServiceInfoFromServiceEvent(arg0);
synchronized (serviceListeners) {
Vector v = (Vector) serviceListeners.get(arg0.getType());
if (v != null) {
for (Iterator i = v.iterator(); i.hasNext();) {
IServiceListener l = (IServiceListener) i.next();
l.serviceRemoved(new ServiceContainerEvent(iinfo, config
.getID()));
}
}
}
}
protected void fireServiceResolved(ServiceEvent arg0) {
IServiceInfo iinfo = createIServiceInfoFromServiceEvent(arg0);
synchronized (serviceListeners) {
Vector v = (Vector) serviceListeners.get(arg0.getType());
if (v != null) {
for (Iterator i = v.iterator(); i.hasNext();) {
IServiceListener l = (IServiceListener) i.next();
l.serviceResolved(new ServiceContainerEvent(iinfo, config
.getID()));
}
}
}
}
protected void fireServiceTypeAdded(ServiceEvent arg0) {
synchronized (serviceTypeListeners) {
for (Iterator i = serviceTypeListeners.iterator(); i.hasNext();) {
IServiceTypeListener l = (IServiceTypeListener) i.next();
l.serviceTypeAdded(new ServiceContainerEvent(
createIServiceInfoFromServiceEvent(arg0), config
.getID()));
}
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.core.IContainer#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if (adapter.isInstance(this)) {
return this;
} else {
IAdapterManager adapterManager = JMDNSPlugin.getDefault().getAdapterManager();
if (adapterManager == null) return null;
return adapterManager.getAdapter(this, adapter);
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.core.IContainer#getConnectedID()
*/
public ID getConnectedID() {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.ecf.discovery.IDiscoveryContainerAdapter#getServiceInfo(org.eclipse.ecf.discovery.identity.IServiceID, int)
*/
public IServiceInfo getServiceInfo(IServiceID service, int timeout) {
Trace.entering(JMDNSPlugin.PLUGIN_ID,
JMDNSDebugOptions.METHODS_ENTERING, this.getClass(),
"getServiceInfo",
new Object[] { service, new Integer(timeout) });
IServiceInfo result = null;
if (jmdns != null)
result = createIServiceInfoFromServiceInfo(jmdns
.getServiceInfo(service.getServiceType(), service
.getServiceName(), timeout));
Trace.exiting(JMDNSPlugin.PLUGIN_ID,
JMDNSDebugOptions.METHODS_ENTERING, this.getClass(),
"getServiceInfo", result);
return result;
}
/* (non-Javadoc)
* @see org.eclipse.ecf.discovery.IDiscoveryContainerAdapter#getServices(java.lang.String)
*/
public IServiceInfo[] getServices(String type) {
IServiceInfo svs[] = new IServiceInfo[0];
if (jmdns != null) {
ServiceInfo[] svcs = jmdns.list(type);
if (svcs != null) {
svs = new IServiceInfo[svcs.length];
for (int i = 0; i < svcs.length; i++) {
svs[i] = createIServiceInfoFromServiceInfo(svcs[i]);
}
}
}
return svs;
}
/* (non-Javadoc)
* @see org.eclipse.ecf.core.IContainer#connect(org.eclipse.ecf.core.identity.ID, org.eclipse.ecf.core.security.IConnectContext)
*/
public void connect(ID groupID, IConnectContext joinContext)
throws ContainerConnectException {
if (this.jmdns != null)
throw new ContainerConnectException("Already connected");
fireContainerEvent(new ContainerConnectingEvent(this.getID(), groupID,
joinContext));
try {
this.jmdns = new JmDNS(intf);
jmdns.addServiceTypeListener(this);
if (groupID != null && groupID instanceof JMDNSServiceID) {
ServiceID svcid = (ServiceID) groupID;
jmdns.addServiceListener(svcid.getServiceType(), this);
}
} catch (IOException e) {
ContainerConnectException soe = new ContainerConnectException(
"Exception creating JmDNS instance");
throw soe;
}
fireContainerEvent(new ContainerConnectedEvent(this.getID(), groupID));
}
/* (non-Javadoc)
* @see org.eclipse.ecf.core.IContainer#disconnect()
*/
public void disconnect() {
fireContainerEvent(new ContainerDisconnectingEvent(this.getID(),
getConnectedID()));
if (this.jmdns != null) {
jmdns.close();
jmdns = null;
}
fireContainerEvent(new ContainerDisconnectedEvent(this.getID(),
getConnectedID()));
}
protected IServiceInfo createIServiceInfoFromServiceEvent(ServiceEvent event) {
ServiceID sID = createServiceID(event.getType(), event.getName());
ServiceInfo sinfo = event.getInfo();
if (sinfo != null) {
return createIServiceInfoFromServiceInfo(sinfo);
}
IServiceInfo newInfo = new JMDNSServiceInfo(null, sID, -1, -1, -1,
new ServiceProperties());
return newInfo;
}
protected IServiceInfo createIServiceInfoFromServiceInfo(
final ServiceInfo serviceInfo) {
if (serviceInfo == null)
return null;
ServiceID sID = createServiceID(serviceInfo.getType(), serviceInfo
.getName());
InetAddress addr = serviceInfo.getAddress();
int port = serviceInfo.getPort();
int priority = serviceInfo.getPriority();
int weight = serviceInfo.getWeight();
Properties props = new Properties();
for (Enumeration e = serviceInfo.getPropertyNames(); e
.hasMoreElements();) {
String name = (String) e.nextElement();
Object value = serviceInfo.getPropertyString(name);
if (value == null)
value = serviceInfo.getPropertyBytes(name);
if (value != null)
props.put(name, value);
}
final ServiceProperties svcProperties = new ServiceProperties(props);
IServiceProperties newProps = new IServiceProperties() {
public Enumeration getPropertyNames() {
return svcProperties.getPropertyNames();
}
public String getPropertyString(String name) {
return svcProperties.getPropertyString(name);
}
public byte[] getPropertyBytes(String name) {
return svcProperties.getPropertyBytes(name);
}
public Object getProperty(String name) {
return svcProperties.getPropertyBytes(name);
}
public Object setProperty(String name, Object value) {
return svcProperties.setProperty(name, value);
}
public Object setPropertyBytes(String name, byte[] value) {
return svcProperties.setPropertyBytes(name, value);
}
public Object setPropertyString(String name, String value) {
return svcProperties.setPropertyString(name, value);
}
};
IServiceInfo newInfo = new JMDNSServiceInfo(addr, sID, port, priority,
weight, newProps);
return newInfo;
}
protected ServiceID createServiceID(String type, String name) {
ServiceID id = null;
try {
id = (ServiceID) IDFactory.getDefault().createID(
JMDNS_NAMESPACE_ID, new Object[] { type, name });
} catch (IDCreateException e) {
// Should never happen
Trace.catching(JMDNSPlugin.PLUGIN_ID,
JMDNSDebugOptions.EXCEPTIONS_CATCHING, this.getClass(),
"createServiceID", e);
}
return id;
}
protected ServiceInfo createServiceInfoFromIServiceInfo(
IServiceInfo serviceInfo) {
if (serviceInfo == null)
return null;
IServiceID sID = serviceInfo.getServiceID();
Hashtable props = new Hashtable();
IServiceProperties svcProps = serviceInfo.getServiceProperties();
if (svcProps != null) {
for (Enumeration e = svcProps.getPropertyNames(); e
.hasMoreElements();) {
String key = (String) e.nextElement();
Object val = svcProps.getProperty(key);
if (val != null) {
props.put(key, val);
}
}
}
ServiceInfo si = new ServiceInfo(sID.getServiceType(), sID
.getServiceName(), serviceInfo.getPort(), serviceInfo
.getPriority(), serviceInfo.getWeight(), props);
return si;
}
protected String prepareSvcTypeForBonjour(String svcType) {
String result = svcType;
if (svcType.endsWith(".local.")) {
result = svcType.substring(0, svcType.indexOf(".local."));
}
return result;
}
/* (non-Javadoc)
* @see org.eclipse.ecf.discovery.IDiscoveryContainerAdapter#registerService(org.eclipse.ecf.discovery.IServiceInfo)
*/
public void registerService(IServiceInfo serviceInfo) throws ECFException {
try {
registerServiceWithJmDNS(serviceInfo);
} catch (IOException e) {
throw new ECFException("registerService",e);
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.discovery.IDiscoveryContainerAdapter#registerServiceType(java.lang.String)
*/
public void registerServiceType(String serviceType) {
if (jmdns != null) {
jmdns.registerServiceType(serviceType);
jmdns.addServiceListener(serviceType, this);
}
}
protected void registerServiceWithJmDNS(IServiceInfo serviceInfo)
throws IOException {
if (jmdns != null) {
jmdns
.registerService(createServiceInfoFromIServiceInfo(serviceInfo));
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.discovery.IDiscoveryContainerAdapter#removeServiceListener(java.lang.String, org.eclipse.ecf.discovery.IServiceListener)
*/
public void removeServiceListener(String type, IServiceListener listener) {
if (type == null || listener == null)
return;
synchronized (serviceListeners) {
Vector v = (Vector) serviceListeners.get(type);
if (v == null) {
return;
}
v.remove(listener);
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.discovery.IDiscoveryContainerAdapter#removeServiceTypeListener(org.eclipse.ecf.discovery.IServiceTypeListener)
*/
public void removeServiceTypeListener(IServiceTypeListener listener) {
serviceTypeListeners.add(listener);
}
/* (non-Javadoc)
* @see org.eclipse.ecf.discovery.IDiscoveryContainerAdapter#requestServiceInfo(org.eclipse.ecf.discovery.identity.IServiceID, int)
*/
public void requestServiceInfo(IServiceID service, int timeout) {
if (jmdns != null) {
jmdns.requestServiceInfo(service.getServiceType(), service
.getServiceName(), timeout);
}
}
public void serviceAdded(ServiceEvent arg0) {
if (jmdns != null) {
try {
fireServiceAdded(arg0);
} catch (Exception e) {
Trace.catching(JMDNSPlugin.PLUGIN_ID,
JMDNSDebugOptions.EXCEPTIONS_CATCHING, this.getClass(),
"serviceAdded", e);
}
}
}
public void serviceRemoved(ServiceEvent arg0) {
if (jmdns != null) {
try {
fireServiceRemoved(arg0);
} catch (Exception e) {
Trace.catching(JMDNSPlugin.PLUGIN_ID,
JMDNSDebugOptions.EXCEPTIONS_CATCHING, this.getClass(),
"serviceRemoved", e);
}
}
}
public void serviceResolved(ServiceEvent arg0) {
if (jmdns != null) {
try {
fireServiceResolved(arg0);
} catch (Exception e) {
Trace.catching(JMDNSPlugin.PLUGIN_ID,
JMDNSDebugOptions.EXCEPTIONS_CATCHING, this.getClass(),
"serviceResolved", e);
}
}
}
public void serviceTypeAdded(ServiceEvent arg0) {
if (jmdns != null) {
try {
fireServiceTypeAdded(arg0);
} catch (Exception e) {
Trace.catching(JMDNSPlugin.PLUGIN_ID,
JMDNSDebugOptions.EXCEPTIONS_CATCHING, this.getClass(),
"serviceResolved", e);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.discovery.IDiscoveryContainerAdapter#unregisterService(org.eclipse.ecf.discovery.IServiceInfo)
*/
public void unregisterService(IServiceInfo serviceInfo) {
if (jmdns != null) {
jmdns
.unregisterService(createServiceInfoFromIServiceInfo(serviceInfo));
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.core.IContainer#getConnectNamespace()
*/
public Namespace getConnectNamespace() {
return IDFactory.getDefault().getNamespaceByName(JMDNS_NAMESPACE_ID);
}
/* (non-Javadoc)
* @see org.eclipse.ecf.core.IContainer#addListener(org.eclipse.ecf.core.IContainerListener)
*/
public void addListener(IContainerListener l) {
synchronized (listeners) {
listeners.add(l);
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.core.IContainer#removeListener(org.eclipse.ecf.core.IContainerListener)
*/
public void removeListener(IContainerListener l) {
synchronized (listeners) {
listeners.remove(l);
}
}
}