/*******************************************************************************
* Copyright (c) 2009 MATERNA Information & Communications. 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. For further
* project-related information visit http://www.ws4d.org. The most recent
* version of the JMEDS framework can be obtained from
* http://sourceforge.net/projects/ws4d-javame.
******************************************************************************/
package org.ws4d.java.communication;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import org.ws4d.java.DPWSFramework;
import org.ws4d.java.attachment.Attachment;
import org.ws4d.java.attachment.AttachmentException;
import org.ws4d.java.communication.DPWS2006.DefaultDPWSCommunicatonUtil;
import org.ws4d.java.communication.connection.ip.IPAddress;
import org.ws4d.java.communication.connection.ip.IPNetworkDetection;
import org.ws4d.java.communication.connection.ip.NetworkInterface;
import org.ws4d.java.communication.monitor.ResourceLoader;
import org.ws4d.java.communication.protocol.http.HTTPGroup;
import org.ws4d.java.communication.protocol.http.HTTPClient;
import org.ws4d.java.communication.protocol.http.HTTPClientDestination;
import org.ws4d.java.communication.protocol.http.HTTPRequest;
import org.ws4d.java.communication.protocol.http.HTTPRequestUtil;
import org.ws4d.java.communication.protocol.http.server.DefaultHTTPResourceHandler;
import org.ws4d.java.communication.protocol.http.server.HTTPServer;
import org.ws4d.java.communication.protocol.mime.DefaultMIMEHandler;
import org.ws4d.java.communication.protocol.mime.MIMEBodyHeader;
import org.ws4d.java.communication.protocol.soap.SOAPRequest;
import org.ws4d.java.communication.protocol.soap.SOAPoverUDPClient;
import org.ws4d.java.communication.protocol.soap.SOAPoverUDPClient.SOAPoverUDPHandler;
import org.ws4d.java.communication.protocol.soap.generator.MessageReceiver;
import org.ws4d.java.communication.protocol.soap.generator.SOAPMessageGeneratorFactory;
import org.ws4d.java.communication.protocol.soap.server.SOAPServer;
import org.ws4d.java.communication.protocol.soap.server.SOAPServer.SOAPHandler;
import org.ws4d.java.communication.protocol.soap.server.SOAPoverUDPServer;
import org.ws4d.java.configuration.DPWSProperties;
import org.ws4d.java.configuration.DispatchingProperties;
import org.ws4d.java.configuration.Properties;
import org.ws4d.java.constants.ConstantsHelper;
import org.ws4d.java.constants.DPWSConstants;
import org.ws4d.java.constants.DPWSConstants2006;
import org.ws4d.java.constants.DPWSMessageConstants;
import org.ws4d.java.constants.HTTPConstants;
import org.ws4d.java.constants.MIMEConstants;
import org.ws4d.java.constants.PrefixRegistry;
import org.ws4d.java.constants.WSAConstants;
import org.ws4d.java.constants.WSAConstants2006;
import org.ws4d.java.dispatch.MessageInformer;
import org.ws4d.java.dispatch.RequestResponseCoordinator;
import org.ws4d.java.message.Message;
import org.ws4d.java.message.SOAPHeader;
import org.ws4d.java.message.metadata.GetMetadataMessage;
import org.ws4d.java.structures.ArrayList;
import org.ws4d.java.structures.DataStructure;
import org.ws4d.java.structures.HashMap;
import org.ws4d.java.structures.HashSet;
import org.ws4d.java.structures.Iterator;
import org.ws4d.java.structures.LinkedSet;
import org.ws4d.java.structures.List;
import org.ws4d.java.structures.MessageIdBuffer;
import org.ws4d.java.structures.Set;
import org.ws4d.java.types.InternetMediaType;
import org.ws4d.java.types.QNameSet;
import org.ws4d.java.types.URI;
import org.ws4d.java.types.XAddressInfo;
import org.ws4d.java.util.Log;
import org.ws4d.java.util.MIMEUtil;
import org.ws4d.java.util.WS4DIllegalStateException;
/**
*
*/
public class DPWSCommunicationManager implements CommunicationManager {
public static final String COMMUNICATION_MANAGER_ID = "DPWS";
private static final Random RND = new Random();
private static final MessageReceiver GENERIC_RECEIVER = new GenericReceiver();
private static final MessageInformer MESSAGE_INFORMER = MessageInformer.getInstance();
private static final CommunicationUtil DPWS_UTIL = DefaultDPWSCommunicatonUtil.getInstance();
protected static final MessageIdBuffer SENT_MULTICAST_MESSAGE_IDS = new MessageIdBuffer();
private volatile boolean stopped = true;
// key = DPWSDomain, value = SOAPoverUDPClient
private final HashMap udpClientsPerDomain = new HashMap();
// contains either the IPv4 or the IPv6 based multicast UDP server, or both
private final HashMap udpServers = new HashMap();
// key = host ':' port, value = SOAPServer
private final HashMap soapServers = new HashMap();
// key = host ':' port, value = HTTPServer
private final HashMap httpServers = new HashMap();
private final RequestResponseCoordinator rrc = RequestResponseCoordinator.getInstance();
private final SOAPoverUDPHandler udpResponseHandler = new SOAPoverUDPHandler(new UDPResponseReceiver(rrc));
private static Set registerForGetMetadata = new HashSet();
private static Set MessageIDsForGetMetadataMapping = new HashSet();
private final Object udpTransmissionsLock = new Object();
private volatile int pendingUDPTransmissions = 0;
private DataStructure domains = getAvailableDomains();
private DataStructure discoveryBindings = null;
public static Set getRegisterForGetMetadata() {
return registerForGetMetadata;
}
public static Set getMessageIDsForGetMetadataMapping() {
return MessageIDsForGetMetadataMapping;
}
public static boolean hasSentMessage(URI messageId) {
return SENT_MULTICAST_MESSAGE_IDS.contains(messageId);
}
/**
* Public default constructor, needed for reflective instance creation (
* <code>Class.forName(...)</code>).
*/
public DPWSCommunicationManager() {
super();
}
/*
* (non-Javadoc)
* @see org.ws4d.java.communication.CommunicationManager#init()
*/
public void init() {
Properties.getInstance().register(Properties.HEADER_SECTION_DPWS, Properties.DPWS_PROPERTIES_HANDLER_CLASS);
Properties.getInstance().register(Properties.HEADER_SECTION_HTTP, Properties.HTTP_PROPERTIES_HANDLER_CLASS);
Properties.getInstance().register(Properties.HEADER_SECTION_IP, Properties.IP_PROPERTIES_HANDLER_CLASS);
PrefixRegistry.addPrefix(DPWSConstants2006.DPWS_NAMESPACE_NAME, DPWSConstants2006.DPWS_NAMESPACE_PREFIX);
PrefixRegistry.addPrefix(DPWSConstants.DPWS_NAMESPACE_NAME, DPWSConstants.DPWS_NAMESPACE_PREFIX);
}
/**
* @return
*/
public String getCommunicationManagerId() {
return COMMUNICATION_MANAGER_ID;
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.CommunicationManager#getAvailableDomains()
*/
public DataStructure getAvailableDomains() {
if (domains == null) {
domains = new ArrayList();
for (Iterator it = IPNetworkDetection.getInstance().getNetworkInterfaces(); it.hasNext();) {
NetworkInterface ni = (NetworkInterface) it.next();
if (!ni.isUp()) {
if (Log.isDebug()) {
Log.debug("The interface " + ni.getName() + " is not up and running...", Log.DEBUG_LAYER_COMMUNICATION);
}
continue;
}
if (!ni.supportsMulticast()) {
if (Log.isDebug()) {
Log.debug("The interface " + ni.getName() + " does not support multicast. No listener will be bound.", Log.DEBUG_LAYER_COMMUNICATION);
}
continue;
}
for (Iterator it2 = ni.getAddresses(); it2.hasNext();) {
IPAddress address = (IPAddress) it2.next();
domains.add(new DPWSDomain(ni, address, true, true));
}
}
}
return domains;
}
public DataStructure refreshAvailableDomains() {
this.domains = null;
return getAvailableDomains();
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.CommunicationManager#addressMatches(org.ws4d
* .java.data.uri.URI, boolean, org.ws4d.java.communication.ProtocolData)
*/
public boolean addressMatches(URI xAddr, boolean source, ProtocolData protocolData) {
if (!(protocolData instanceof DPWSProtocolData)) {
return false;
}
DPWSProtocolData data = (DPWSProtocolData) protocolData;
String otherAddr = getCanonicalAddress(source ? data.getSourceHost() : data.getDestinationHost());
String hostAddr = getCanonicalAddress(xAddr.getHost());
return otherAddr != null && otherAddr.equals(hostAddr);
}
public long getRandomApplicationDelay(int version) {
CommunicationUtil comUtil = getCommunicationUtil();
ConstantsHelper helper = comUtil.getHelper(version);
int max = helper.getRandomApplicationDelay();
if (max <= 0) {
return 0;
}
int delay = RND.nextInt();
if (delay < 0) {
delay = -delay;
}
return delay % (max + 1);
}
public void start() throws IOException {
if (!stopped) {
return;
}
stopped = false;
if (Log.isInfo()) {
Log.info(DPWSProperties.getInstance().printSupportedDPWSVersions());
}
}
public DataStructure getDiscoveryBindings() throws IOException {
if (discoveryBindings != null) {
return discoveryBindings;
}
DataStructure domains = getAvailableDomains();
discoveryBindings = new LinkedSet();
for (Iterator it = domains.iterator(); it.hasNext();) {
ProtocolDomain domain = (ProtocolDomain) it.next();
discoveryBindings.add(getDiscoveryBindingForDomain(domain));
}
return discoveryBindings;
}
/**
* Unsupported
*/
public DiscoveryBinding getDiscoveryBindingForDomain(ProtocolDomain domain) throws IOException {
if (!(domain instanceof DPWSDomain)) {
throw new IOException("Unsupported Domain: " + domain);
}
DPWSDomain dpwsDomain = (DPWSDomain) domain;
int type = (dpwsDomain.getIPAddress().isIPv6()) ? 6 : 4;
DPWSDiscoveryBinding discovery = new DPWSDiscoveryBinding(type, dpwsDomain.getInterfaceName());
Log.info("Add discovery binding: " + discovery);
return discovery;
}
public DiscoveryBinding getDiscoveryBindingForProtocolData(ProtocolData data) {
String address = data.getDestinationAddress();
String iFace = data.getIFace();
DPWSDiscoveryBinding binding = null;
if (address.indexOf(':') == -1) {
// ipV4:
binding = new DPWSDiscoveryBinding(4, iFace);
} else {
// ipV6:
binding = new DPWSDiscoveryBinding(6, iFace);
}
return binding;
}
/**
*/
public DataStructure getDiscoveryDomainForBinding(DiscoveryBinding binding) throws IOException {
if (binding == null) {
throw new IOException("No spezcified binding");
}
if (!(binding instanceof DPWSDiscoveryBinding)) {
throw new IOException("Wrong Binding: " + binding);
}
ArrayList test = new ArrayList();
DPWSDiscoveryBinding bind = (DPWSDiscoveryBinding) binding;
for (Iterator iterator = ((ArrayList) getAvailableDomains()).iterator(); iterator.hasNext();) {
DPWSDomain domain = (DPWSDomain) iterator.next();
int ipVersion = domain.getIPAddress().isIPv6() ? 6 : 4;
if (domain.getInterfaceName().equals(bind.getIface()) && ipVersion == bind.ipVersion) {
test.add(domain);
}
}
if (test.size() == 0) {
throw new IOException("No Domain found for Binding: " + binding);
}
return test;
}
/*
* (non-Javadoc)
* @see org.ws4d.java.communication.CommunicationManager#kill()
*/
public void kill() {
stopInternal(true);
}
/*
* (non-Javadoc)
* @see org.ws4d.java.communication.CommunicationManager#shutdown()
*/
public void stop() {
stopInternal(false);
}
private void stopInternal(boolean kill) {
if (stopped) {
return;
}
synchronized (udpTransmissionsLock) {
while (pendingUDPTransmissions > 0) {
try {
udpTransmissionsLock.wait();
} catch (InterruptedException e) {
// ignore
}
}
// close servers first
synchronized (udpServers) {
for (Iterator it = udpServers.values().iterator(); it.hasNext();) {
SOAPoverUDPServer server = (SOAPoverUDPServer) it.next();
try {
server.stop();
} catch (IOException e) {
Log.error("Unable to close SOAPoverUDPServer: " + e);
Log.printStackTrace(e);
}
}
udpServers.clear();
}
synchronized (soapServers) {
for (Iterator it = soapServers.values().iterator(); it.hasNext();) {
SOAPServer server = (SOAPServer) it.next();
try {
SOAPServer.unregisterAndStop(server);
} catch (IOException e) {
Log.error("Unable to close SOAPServer: " + e);
Log.printStackTrace(e);
}
}
soapServers.clear();
}
SOAPMessageGeneratorFactory.clear();
synchronized (httpServers) {
for (Iterator it = httpServers.values().iterator(); it.hasNext();) {
HTTPServer server = (HTTPServer) it.next();
try {
HTTPServer.unregisterAndStop(server);
} catch (IOException e) {
Log.error("Unable to close HTTPServer: " + e);
Log.printStackTrace(e);
}
}
httpServers.clear();
}
// now close clients, too
synchronized (udpClientsPerDomain) {
for (Iterator it = udpClientsPerDomain.values().iterator(); it.hasNext();) {
SOAPoverUDPClient client = (SOAPoverUDPClient) it.next();
try {
client.close();
} catch (IOException e) {
Log.error("Unable to close SOAPoverUDPClient: " + e);
Log.printStackTrace(e);
}
}
udpClientsPerDomain.clear();
}
if (kill) {
HTTPClient.killAllClients();
} else {
HTTPClient.closeAllClients();
}
SENT_MULTICAST_MESSAGE_IDS.clear();
stopped = true;
}
}
/**
* Registers a device to receive (TCP) messages on a specified socket.
*
* @param messageTypes Messages to receive. See for example
* DPWSMessageConstants.
* @param binding HttpBinding.
* @param listener
* @throws IOException If the binding type does not match.
* @throws WS4DIllegalStateException
*/
public void registerDevice(int[] messageTypes, CommunicationBinding binding, IncomingMessageListener listener, HTTPGroup user) throws IOException, WS4DIllegalStateException {
checkStopped();
try {
HTTPBinding httpBinding = (HTTPBinding) binding;
SOAPServer server;
if (DPWSFramework.hasModule(DPWSFramework.SECURITY_MODULE)) {
server = getSOAPServer(httpBinding.getHostAddress(), httpBinding.getPort(), httpBinding.getType() == IPBinding.HTTPS_BINDING, DPWSFramework.getSecurityManager().getAliasFromBinding(httpBinding));
} else {
server = getSOAPServer(httpBinding.getHostAddress(), httpBinding.getPort(), httpBinding.getType() == IPBinding.HTTPS_BINDING, null);
}
if (httpBinding.getPort() == 0) {
httpBinding.setPort(server.getHTTPServer().getPort());
}
String path = httpBinding.getPath();
SOAPHandler handler = new IncomingSOAPReceiver(listener);
server.register(path, handler, user);
for (int i = 0; i < messageTypes.length; i++) {
if (DPWSMessageConstants.GET_METADATA_MESSAGE == messageTypes[i]) {
addUriToRegister(httpBinding.getTransportAddress(), registerForGetMetadata);
}
if (DPWSMessageConstants.INVOKE_MESSAGE == messageTypes[i]) {
DefaultMIMEHandler requestHandler = new DefaultMIMEHandler();
requestHandler.register(InternetMediaType.getApplicationXOPXML(), new IncomingMIMEReceiver(listener));
requestHandler.register(2, -1, AttachmentStoreHandler.getInstance());
server.getHTTPServer().register(path, InternetMediaType.getMultipartRelated(), requestHandler, user);
}
}
} catch (ClassCastException e) {
throw new IOException("Unsupported binding type. Need HTTPBinding but was: " + binding);
}
}
/**
* Registers a service to receive (TCP) messages on a specified socket.
*
* @param messageTypes Messages to receive. See for example
* DPWSMessageConstants.
* @param binding HttpBinding.
* @param listener
* @throws IOException If the binding type does not match.
* @throws WS4DIllegalStateException
*/
public void registerService(int[] messageTypes, CommunicationBinding binding, IncomingMessageListener listener, HTTPGroup user) throws IOException, WS4DIllegalStateException {
checkStopped();
try {
HTTPBinding httpBinding = (HTTPBinding) binding;
SOAPServer server;
if (DPWSFramework.hasModule(DPWSFramework.SECURITY_MODULE)) {
server = getSOAPServer(httpBinding.getHostAddress(), httpBinding.getPort(), httpBinding.getType() == IPBinding.HTTPS_BINDING, DPWSFramework.getSecurityManager().getAliasFromBinding(httpBinding));
} else {
server = getSOAPServer(httpBinding.getHostAddress(), httpBinding.getPort(), httpBinding.getType() == IPBinding.HTTPS_BINDING, null);
}
if (httpBinding.getPort() == 0) {
httpBinding.setPort(server.getHTTPServer().getPort());
}
String path = httpBinding.getPath();
SOAPHandler handler = new IncomingSOAPReceiver(listener);
server.register(path, handler, user);
for (int i = 0; i < messageTypes.length; i++) {
if (DPWSMessageConstants.GET_METADATA_MESSAGE == messageTypes[i]) {
addUriToRegister(httpBinding.getTransportAddress(), registerForGetMetadata);
}
if (DPWSMessageConstants.INVOKE_MESSAGE == messageTypes[i]) {
DefaultMIMEHandler requestHandler = new DefaultMIMEHandler();
requestHandler.register(InternetMediaType.getApplicationXOPXML(), new IncomingMIMEReceiver(listener));
if (DPWSFramework.hasModule(DPWSFramework.ATTACHMENT_MODULE)) {
requestHandler.register(2, -1, AttachmentStoreHandler.getInstance());
}
server.getHTTPServer().register(path, InternetMediaType.getMultipartRelated(), requestHandler, user);
}
}
} catch (ClassCastException e) {
throw new IOException("Unsupported binding type. Need HTTPBinding but was: " + binding);
}
}
/**
* Registers the framework to receive (UDP) discovery messages on a
* specified socket.
*
* @param messageTypes Messages to receive. See for example
* DPWSMessageConstants.
* @param binding DiscoveryBinding.
* @param listener
* @throws IOException If the binding type does not match.
* @throws WS4DIllegalStateException
*/
public void registerDeviceReference(int[] messageTypes, DiscoveryBinding binding, IncomingMessageListener listener) throws IOException, WS4DIllegalStateException {
if (binding == null) {
throw new IOException("Parameter \"binding\" must not be null.");
}
checkStopped();
try {
DPWSDiscoveryBinding discoveryBinding = (DPWSDiscoveryBinding) binding;
SOAPoverUDPServer server = getSOAPoverUDPServer(discoveryBinding.getHostAddress(), discoveryBinding.getPort(), discoveryBinding.getIface());
IncomingUDPReceiver receiver = (IncomingUDPReceiver) server.getHandler();
receiver.register(messageTypes, listener);
if (Log.isDebug()) {
Log.debug("Lifecycle discovery over: " + discoveryBinding, Log.DEBUG_LAYER_COMMUNICATION);
}
} catch (ClassCastException e) {
throw new IOException("Unsupported binding type. Need DPWSDiscoveryBinding but was: " + binding);
}
}
/**
* Registers the framework to receive (UDP) discovery messages on a
* specified socket.
*
* @param messageTypes Messages to receive. See for example
* DPWSMessageConstants.
* @param binding DiscoveryBinding.
* @param listener
* @throws IOException If the binding type does not mat
* @throws WS4DIllegalStateException
*/
public void registerDiscovery(int[] messageTypes, DiscoveryBinding binding, IncomingMessageListener listener) throws IOException, WS4DIllegalStateException {
checkStopped();
try {
DPWSDiscoveryBinding discoveryBinding = (DPWSDiscoveryBinding) binding;
SOAPoverUDPServer server = getSOAPoverUDPServer(discoveryBinding.getHostAddress(), discoveryBinding.getPort(), discoveryBinding.getIface());
if (server != null) {
IncomingUDPReceiver receiver = (IncomingUDPReceiver) server.getHandler();
receiver.register(messageTypes, listener);
}
} catch (ClassCastException e) {
throw new IOException("Unsupported binding type. Need DiscoveryBinding but was: " + binding.getClass().getName());
}
}
public void unregisterDevice(int[] messageTypes, CommunicationBinding binding, IncomingMessageListener listener) throws IOException, WS4DIllegalStateException {
checkStopped();
try {
HTTPBinding httpBinding = (HTTPBinding) binding;
if (httpBinding != null) {
SOAPServer server = null;
if (DPWSFramework.hasModule(DPWSFramework.SECURITY_MODULE)) {
server = getSOAPServer(httpBinding.getHostAddress(), httpBinding.getPort(), (httpBinding.getType() == IPBinding.HTTPS_BINDING), DPWSFramework.getSecurityManager().getAliasFromBinding(httpBinding));
} else {
server = getSOAPServer(httpBinding.getHostAddress(), httpBinding.getPort(), (httpBinding.getType() == IPBinding.HTTPS_BINDING), null);
}
String path = httpBinding.getPath();
server.unregister(path);
server.getHTTPServer().unregister(path, InternetMediaType.getMultipartRelated());
httpBinding.resetAutoPort();
}
for (int i = 0; i < messageTypes.length; i++) {
if (DPWSMessageConstants.GET_METADATA_MESSAGE == messageTypes[i]) {
removeUriFromRegister(httpBinding.getTransportAddress(), registerForGetMetadata);
}
}
} catch (ClassCastException e) {
throw new IOException("Unsupported binding type. Need HTTPBinding but was: " + binding);
}
}
public void unregisterService(int[] messageTypes, CommunicationBinding binding, IncomingMessageListener listener) throws IOException, WS4DIllegalStateException {
checkStopped();
try {
HTTPBinding httpBinding = (HTTPBinding) binding;
if (httpBinding != null) {
SOAPServer server = null;
if (DPWSFramework.hasModule(DPWSFramework.SECURITY_MODULE)) {
server = getSOAPServer(httpBinding.getHostAddress(), httpBinding.getPort(), (httpBinding.getType() == IPBinding.HTTPS_BINDING), DPWSFramework.getSecurityManager().getAliasFromBinding(httpBinding));
} else
server = getSOAPServer(httpBinding.getHostAddress(), httpBinding.getPort(), (httpBinding.getType() == IPBinding.HTTPS_BINDING), null);
String path = httpBinding.getPath();
server.unregister(path);
server.getHTTPServer().unregister(path, InternetMediaType.getMultipartRelated());
httpBinding.resetAutoPort();
}
for (int i = 0; i < messageTypes.length; i++) {
if (DPWSMessageConstants.GET_METADATA_MESSAGE == messageTypes[i]) {
removeUriFromRegister(httpBinding.getTransportAddress(), registerForGetMetadata);
}
}
} catch (ClassCastException e) {
throw new IOException("Unsupported binding type. Need HTTPBinding but was: " + binding);
}
}
public void unregisterDiscovery(int[] messageTypes, DiscoveryBinding binding, IncomingMessageListener listener) throws IOException, WS4DIllegalStateException {
checkStopped();
if (binding != null) {
try {
DPWSDiscoveryBinding discoveryBinding = (DPWSDiscoveryBinding) binding;
IPAddress hostAddress = discoveryBinding.getHostAddress();
int port = discoveryBinding.getPort();
String ifaceName = discoveryBinding.getIface();
SOAPoverUDPServer server = getSOAPoverUDPServer(hostAddress, port, ifaceName);
if (server != null) {
IncomingUDPReceiver receiver = (IncomingUDPReceiver) server.getHandler();
receiver.unregister(messageTypes, listener);
if (receiver.isEmpty()) {
String key = hostAddress.getAddress() + ":" + port + "%" + ifaceName;
synchronized (udpServers) {
try {
server.stop();
udpServers.remove(key);
} catch (IOException e) {
Log.warn("unable to remove SOAP-over-UDP server for multicast address " + key + ". " + e.getMessage());
}
}
}
}
} catch (ClassCastException e) {
throw new IOException("Unsupported binding type. Need DiscoveryBinding but was: " + binding);
}
}
}
public void unregisterDeviceReference(int[] messageTypes, DiscoveryBinding binding, IncomingMessageListener listener) throws IOException, WS4DIllegalStateException {
checkStopped();
if (binding != null) {
try {
DPWSDiscoveryBinding discoveryBinding = (DPWSDiscoveryBinding) binding;
IPAddress hostAddress = discoveryBinding.getHostAddress();
int port = discoveryBinding.getPort();
String ifaceName = discoveryBinding.getIface();
SOAPoverUDPServer server = getSOAPoverUDPServer(hostAddress, port, ifaceName);
IncomingUDPReceiver receiver = (IncomingUDPReceiver) server.getHandler();
receiver.unregister(messageTypes, listener);
if (receiver.isEmpty()) {
String key = hostAddress.getAddress() + ":" + port + "%" + ifaceName;
synchronized (udpServers) {
try {
server.stop();
udpServers.remove(key);
} catch (IOException e) {
Log.warn("unable to remove SOAP-over-UDP server for multicast address " + key + ". " + e.getMessage());
}
}
}
} catch (ClassCastException e) {
throw new IOException("Unsupported binding type. Need DiscoveryBinding but was: " + binding);
}
}
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.CommunicationManager#deploy(org.ws4d.java
* .communication.Resource,
* org.ws4d.java.communication.CommunicationBinding, java.lang.String)
*/
public URI registerResource(Resource resource, CommunicationBinding binding, String resourcePath, HTTPGroup user) throws IOException, WS4DIllegalStateException {
checkStopped();
if (binding != null && !(binding instanceof HTTPBinding)) {
throw new IOException("Unsupported binding type: " + binding);
}
HTTPBinding httpBinding = (HTTPBinding) binding;
IPAddress host = httpBinding.getHostAddress();
int port = httpBinding.getPort();
HTTPServer server = httpBinding.getType() == IPBinding.HTTPS_BINDING ? getHTTPServer(host, port, true, DPWSFramework.getSecurityManager().getAliasFromBinding(httpBinding)) : getHTTPServer(host, port);
if (port == 0) {
port = server.getPort();
httpBinding.setPort(port);
}
String basicPath = httpBinding.getPath();
if (resourcePath == null) {
resourcePath = "";
} else if (!(resourcePath.startsWith("/") || basicPath.endsWith("/"))) {
resourcePath = "/" + resourcePath;
}
String addressPath = basicPath + resourcePath;
server.register(addressPath, new DefaultHTTPResourceHandler(resource), user);
return new URI((httpBinding.getType() == IPBinding.HTTPS_BINDING ? "https://" : "http://") + host.getAddressWithoutNicId() + ":" + port + addressPath);
}
/*
* (non-Javadoc)
* @see org.ws4d.java.communication.CommunicationManager#undeploy(org.ws4d
* .java.data.uri.URI)
*/
public void unregisterResource(URI deployAddress, CommunicationBinding binding) throws IOException, WS4DIllegalStateException {
HTTPBinding httpBinding;
try {
httpBinding = (HTTPBinding) binding;
} catch (ClassCastException e) {
if (Log.isError()) Log.error("DPWSCommunicationManager.unregisterResource: unsupported CommunicationBinding class (" + binding.getClass() + ")");
return;
}
checkStopped();
int port = deployAddress.getPort();
HTTPServer server = getHTTPServer(httpBinding.getHostAddress(), port);
server.unregister(deployAddress.getPath());
httpBinding.resetAutoPort();
}
/* (non-Javadoc)
* @see org.ws4d.java.communication.CommunicationManager#send(org.ws4d.java.message.Message, org.ws4d.java.types.XAddressInfo, org.ws4d.java.communication.ProtocolDomain, org.ws4d.java.communication.ResponseCallback)
*/
public void send(Message message, XAddressInfo targetXAdrInfo, ProtocolDomain domain, ResponseCallback callback) throws WS4DIllegalStateException {
checkStopped();
/*
* only request messages (including one-way Hello and Bye) can be sent
* by this method
*/
if (message == null) return;
switch (message.getRoutingScheme()) {
case Message.UNICAST_ROUTING_SCHEME: {
if (targetXAdrInfo == null) {
Log.warn("No target address found within request message " + message);
throw new IllegalArgumentException("No target address set for message " + message);
}
sendTCPAndCheckDPWSVersion(message, callback, targetXAdrInfo);
break;
}
case Message.MULTICAST_ROUTING_SCHEME: {
sendUDPMulticastAndCheckDPWSVersion(message, domain, callback);
break;
}
case Message.UNKNOWN_ROUTING_SCHEME:
default: {
Log.warn("Attempt to send a message of an unexpected type: " + message);
throw new IllegalArgumentException("Unexpected message type: " + message);
}
}
// switch (message.getType()) {
// // SOAP/HTTP/TCP messages first
// case (DPWSMessageConstants.GET_MESSAGE):
// case (DPWSMessageConstants.GET_METADATA_MESSAGE):
// case (DPWSMessageConstants.SUBSCRIBE_MESSAGE):
// case (DPWSMessageConstants.GET_STATUS_MESSAGE):
// case (DPWSMessageConstants.RENEW_MESSAGE):
// case (DPWSMessageConstants.UNSUBSCRIBE_MESSAGE):
// case (DPWSMessageConstants.SUBSCRIPTION_END_MESSAGE):
// case (DPWSMessageConstants.INVOKE_MESSAGE): {
// URI targetAddress = message.getTargetAddress();
// if (targetAddress == null) {
// Log.warn("No target address found within request message " +
// message);
// throw new
// IllegalArgumentException("No target address set for message " +
// message);
// }
// sendTCPAndCheckDPWSVersion(message, callback, targetAddress);
// break;
// }
// // SOAP-over-UDP messages
// case (DPWSMessageConstants.HELLO_MESSAGE):
// case (DPWSMessageConstants.BYE_MESSAGE):
// case (DPWSMessageConstants.RESOLVE_MESSAGE): {
// sendUDPMulticastAndCheckDPWSVersion(message, domain, callback);
// break;
// }
// /*
// * special case Probe: it can be either SOAP-over-UDP or
// * SOAP/HTTP/TCP for directed Probes, i.e. when targetAddress !=
// * null
// */
// case (DPWSMessageConstants.PROBE_MESSAGE): {
// URI targetAddress = message.getTargetAddress();
// if (targetAddress == null) {
// // SOAP-over-UDP aka. multicast Probe
// sendUDPMulticastAndCheckDPWSVersion(message, domain, callback);
// } else {
// sendTCPAndCheckDPWSVersion(message, callback, targetAddress);
// }
// break;
// }
// default: {
// Log.warn("Attempt to send a message of an unexpected type: " +
// message);
// throw new IllegalArgumentException("Unexpected message type: " +
// message);
// }
// }
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.CommunicationManager#getResourceAsStream(
* org.ws4d.java.types.URI)
*/
public ResourceLoader getResourceAsStream(URI location) throws IOException {
if (location.getSchema().startsWith(HTTPConstants.HTTP_SCHEMA)) {
try {
return HTTPRequestUtil.getResourceAsStream(location.toString());
} catch (ProtocolException e) {
throw new IOException("HTTP protocol exception.");
}
}
return null;
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.CommunicationManager#getAutobindings(java
* .lang.String, org.ws4d.java.structures.DataStructure)
*/
public void getAutobindings(String descriptor, DataStructure bindings) throws IOException {
checkStopped();
List ipv4Loopback = new ArrayList(4);
List ipv6Loopback = new ArrayList(4);
// 'real' external IPs
List ipv4 = new ArrayList(4);
List ipv6 = new ArrayList(4);
for (Iterator it = getAvailableDomains().iterator(); it.hasNext();) {
DPWSDomain domain = (DPWSDomain) it.next();
IPAddress addr = domain.getIPAddress();
boolean loopbackIface = domain.getIface().isLoopback();
if (addr.isIPv6()) {
if (loopbackIface || addr.isLoopback()) {
ipv6Loopback.add(domain);
} else {
ipv6.add(domain);
}
} else {
// must be v4
if (loopbackIface || addr.isLoopback()) {
ipv4Loopback.add(domain);
} else {
ipv4.add(domain);
}
}
}
// observe IPv4 case first
List srcList = ipv4.isEmpty() ? ipv4Loopback : ipv4;
HashMap ipv4filter = new HashMap();
for (Iterator it = srcList.iterator(); it.hasNext();) {
DPWSDomain domain = (DPWSDomain) it.next();
String ifaceName = domain.getInterfaceName();
if (ipv4filter.containsKey(ifaceName)) {
continue;
}
ipv4filter.put(ifaceName, domain);
}
// TODO
// observe IPv6 case
srcList = ipv6.isEmpty() ? ipv6Loopback : ipv6;
HashMap ipv6filter = new HashMap();
for (Iterator it = srcList.iterator(); it.hasNext();) {
DPWSDomain domain = (DPWSDomain) it.next();
String ifaceName = domain.getInterfaceName();
DPWSDomain otherDomain = (DPWSDomain) ipv6filter.get(ifaceName);
if (otherDomain != null) {
if (otherDomain.getIface().isLoopback()) {
if (otherDomain.getIPAddress().isLoopback()) {
continue;
}
} else if (otherDomain.getIPAddress().isIPv6LinkLocal()) {
continue;
}
}
ipv6filter.put(ifaceName, domain);
}
bindAddresses(descriptor, bindings, ipv4filter.values());
bindAddresses(descriptor, bindings, ipv6filter.values());
}
private void bindAddresses(String descriptor, DataStructure bindings, DataStructure domains) {
for (Iterator it = domains.iterator(); it.hasNext();) {
DPWSDomain domain = (DPWSDomain) it.next();
HTTPBinding binding = new HTTPBinding(domain.getIPAddress(), 0, descriptor);
if (Log.isDebug()) {
Log.debug("Adding HTTP auto-binding on " + domain.getInterfaceName() + ": " + binding, Log.DEBUG_LAYER_COMMUNICATION);
}
bindings.add(binding);
}
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.CommunicationManager#getProtocolDomains(org
* .ws4d.java.structures.Iterator, org.ws4d.java.structures.DataStructure)
*/
public void getProtocolDomains(Iterator bindings, DataStructure domains) throws IOException {
DataStructure ourDomains = getAvailableDomains();
while (bindings.hasNext()) {
Object o = bindings.next();
if (!(o instanceof HTTPBinding)) {
continue;
}
IPAddress bindingIPAddr = ((HTTPBinding) o).getHostAddress();
for (Iterator it = ourDomains.iterator(); it.hasNext();) {
DPWSDomain d = (DPWSDomain) it.next();
if (d.getIPAddress().equals(bindingIPAddr)) {
domains.add(d);
break;
}
}
}
}
private void checkStopped() throws WS4DIllegalStateException {
if (stopped) {
throw new WS4DIllegalStateException("this communication manager is stopped");
}
}
/**
* Method checks the supported DPWSVersions from the DPWSProperties. If in
* the Properties no DPWS Version is defined the user is a nerd. If there is
* one DPWSVersion defined, it will be set to the message, else if more than
* one DPWSVersion is defined nothing will be done.
*
* @param message , the message which checks for Version.
*/
private void checkSupportedDPWSVersions(Message message) {
HashSet supportedDPWSVersions = DPWSProperties.getInstance().getSupportedDPWSVersions();
if (message.getProtocolInfo() == null && supportedDPWSVersions.size() == 1) {
Iterator it = supportedDPWSVersions.iterator();
Integer i = (Integer) it.next();
message.setProtocolInfo(new DPWSProtocolInfo(i.intValue()));
return;
} else if (message.getProtocolInfo() != null) {
if (!supportedDPWSVersions.contains(new Integer(message.getProtocolInfo().getVersion()))) {
Iterator it = supportedDPWSVersions.iterator();
Integer i = (Integer) it.next();
message.setProtocolInfo(new DPWSProtocolInfo(i.intValue()));
if (Log.isDebug()) {
Log.debug("The choosen DPWS Versio is not supported, changed to " + message.getProtocolInfo().getDisplayName() + ".", Log.DEBUG_LAYER_COMMUNICATION);
}
}
return;
}
}
protected SOAPoverUDPServer getSOAPoverUDPServer(IPAddress localHostAddress, int port, String ifaceName) {
String key = localHostAddress.getAddress() + ":" + port + "%" + ifaceName;
SOAPoverUDPServer server = null;
synchronized (udpServers) {
server = (SOAPoverUDPServer) udpServers.get(key);
if (server == null || !server.isRunning()) {
try {
server = new SOAPoverUDPServer(localHostAddress, port, ifaceName, new IncomingUDPReceiver());
udpServers.put(key, server);
} catch (IOException e) {
Log.warn("Unable to create SOAP-over-UDP server for multicast address " + key + ". " + e.getMessage());
}
}
}
return server;
}
private SOAPServer getSOAPServer(IPAddress localHostAddress, int port, boolean secure, String alias) throws IOException {
String localAddress;
SOAPServer server;
if (port == 0) {
server = SOAPServer.get(localHostAddress, port, secure, alias);
localAddress = localHostAddress.getAddress() + ":" + server.getHTTPServer().getPort();
synchronized (soapServers) {
soapServers.put(localAddress, server);
}
} else {
localAddress = localHostAddress.getAddress() + ":" + port;
synchronized (soapServers) {
server = (SOAPServer) soapServers.get(localAddress);
if (server == null || !server.getHTTPServer().isRunning()) {
server = SOAPServer.get(localHostAddress, port, secure, alias);
soapServers.put(localAddress, server);
} else {
return server;
}
}
}
// cache the underlying HTTP server, too
HTTPServer httpServer = server.getHTTPServer();
synchronized (httpServers) {
httpServers.put(localAddress, httpServer);
}
return server;
}
private HTTPServer getHTTPServer(IPAddress localHostAddress, int port) throws IOException {
return getHTTPServer(localHostAddress, port, false, null);
}
private HTTPServer getHTTPServer(IPAddress localHostAddress, int port, boolean secure, String alias) throws IOException {
HTTPServer server;
if (port == 0) {
server = HTTPServer.get(localHostAddress, port, secure, alias);
synchronized (httpServers) {
httpServers.put(localHostAddress.getAddress() + ":" + server.getPort(), server);
}
return server;
}
String localAddress = localHostAddress.getAddress() + ":" + port;
synchronized (httpServers) {
server = (HTTPServer) httpServers.get(localAddress);
if (server == null || !server.isRunning()) {
server = HTTPServer.get(localHostAddress, port, secure, alias);
httpServers.put(localAddress, server);
}
}
return server;
}
private String getCanonicalAddress(String address) {
/*
* be aware of alias addresses, like localhost vs. 127.0.0.1 or DNS
* aliases, etc. map them all to a single canonical form, e.g. IPv4
* address
*/
return IPNetworkDetection.getInstance().getCanonicalAddress(address);
}
private void addUriToRegister(URI uri, Set register) {
/*
* in case the URI's host is given as a DNS name, it is important to add
* another URI with the equivalent IP address to the register in order
* to find it when searching for it with the value returned from
* DPWSProtocolData.getTransportAddress() (which will rather contain an
* IP address)
*/
register.add(uri);
URI canonicalUri = createCanonicalUri(uri);
if (canonicalUri != null) {
register.add(canonicalUri);
}
}
private void removeUriFromRegister(URI uri, Set register) {
register.remove(uri);
URI canonicalUri = createCanonicalUri(uri);
if (canonicalUri != null) {
register.remove(canonicalUri);
}
}
private URI createCanonicalUri(URI srcUri) {
String host = srcUri.getHost();
if (host == null || "".equals(host)) {
return null;
}
String canonicalHost = getCanonicalAddress(host);
if (host.equals(canonicalHost)) {
return null;
}
String s = srcUri.toString();
int hostIndex = s.indexOf(host);
// replace original host with canonical one
s = s.substring(0, hostIndex) + canonicalHost + s.substring(hostIndex + host.length());
URI canonicalUri = new URI(s);
return canonicalUri;
}
protected void sendTCPAndCheckDPWSVersion(final Message message, final ResponseCallback callback, final XAddressInfo targetXAdrInfo) {
Runnable r = new Runnable() {
public void run() {
// Checks and set the DPWS Version of the Message
checkSupportedDPWSVersions(message);
if (targetXAdrInfo.getProtocolInfo() == null || targetXAdrInfo.getProtocolInfo().getVersion() == DPWSProtocolInfo.DPWS_VERSION_NOT_SET) {
/*
* in that case we must potentially send multiple copies of
* the message - one per supported version; thereby, we must
* be able to intercept any faults in response resulting
* from version mismatch
*/
ResponseCallback faultAwareCallback = new FaultAwareResponseCallback(targetXAdrInfo, callback, 2);
HashSet supportedVersions = DPWSProperties.getInstance().getSupportedDPWSVersions();
if (supportedVersions.contains(new Integer(DPWSConstants.DPWS_VERSION2009))) {
Message dpws1_1 = DPWS_UTIL.copyOutgoingMessage(message);
dpws1_1.setProtocolInfo(new DPWSProtocolInfo(DPWSConstants.DPWS_VERSION2009));
sendTCP(dpws1_1, faultAwareCallback, targetXAdrInfo.getXAddress());
}
if (supportedVersions.contains(new Integer(DPWSConstants2006.DPWS_VERSION2006))) {
Message dpws2006 = DPWS_UTIL.copyOutgoingMessage(message);
if (message instanceof GetMetadataMessage) {
// changing the GetMetadataMessage to GetMessage
Message msgGetFromGetMetadata = DPWS_UTIL.changeOutgoingMessage(DPWSConstants2006.DPWS_VERSION2006, (GetMetadataMessage) dpws2006);
msgGetFromGetMetadata.setProtocolInfo(new DPWSProtocolInfo(DPWSConstants2006.DPWS_VERSION2006));
MessageIDsForGetMetadataMapping.add(msgGetFromGetMetadata.getMessageId());
sendTCP(msgGetFromGetMetadata, callback, targetXAdrInfo.getXAddress());
} else {
// here just attributs must be changed
Message changedMessage2006 = DPWS_UTIL.changeOutgoingMessage(DPWSConstants2006.DPWS_VERSION2006, dpws2006);
changedMessage2006.setProtocolInfo(new DPWSProtocolInfo(DPWSConstants2006.DPWS_VERSION2006));
sendTCP(changedMessage2006, callback, targetXAdrInfo.getXAddress());
}
}
} else {
if (Log.isDebug()) {
Log.debug("Send " + message.getProtocolInfo().getDisplayName() + " Message", Log.DEBUG_LAYER_COMMUNICATION);
}
if (message.getProtocolInfo().getVersion() == DPWSConstants2006.DPWS_VERSION2006) {
Message dpws2006 = DPWS_UTIL.copyOutgoingMessage(message);
if (message instanceof GetMetadataMessage) {
// changing the GetMetadataMessage to GetMessage
Message msgGetFromGetMetadata = DPWS_UTIL.changeOutgoingMessage(message.getProtocolInfo().getVersion(), (GetMetadataMessage) dpws2006);
msgGetFromGetMetadata.setProtocolInfo(new DPWSProtocolInfo(DPWSConstants2006.DPWS_VERSION2006));
MessageIDsForGetMetadataMapping.add(msgGetFromGetMetadata.getMessageId());
sendTCP(msgGetFromGetMetadata, callback, targetXAdrInfo.getXAddress());
} else {
// here just attributs must be changed
Message changedMessage2006 = DPWS_UTIL.changeOutgoingMessage(message.getProtocolInfo().getVersion(), dpws2006);
changedMessage2006.setProtocolInfo(new DPWSProtocolInfo(DPWSConstants2006.DPWS_VERSION2006));
sendTCP(changedMessage2006, callback, targetXAdrInfo.getXAddress());
}
} else {
sendTCP(message, callback, targetXAdrInfo.getXAddress());
}
}
}
};
DPWSFramework.getThreadPool().execute(r);
}
protected void sendUDPMulticastAndCheckDPWSVersion(final Message message, final ProtocolDomain domain, final ResponseCallback callback) {
// Checks and set the DPWS Version of the Message
checkSupportedDPWSVersions(message);
synchronized (udpTransmissionsLock) {
pendingUDPTransmissions++;
if (message.getProtocolInfo() == null) {
pendingUDPTransmissions++;
}
}
if (message.getProtocolInfo() == null || message.getProtocolInfo().getVersion() == DPWSProtocolInfo.DPWS_VERSION_NOT_SET) {
HashSet supportedVersions = DPWSProperties.getInstance().getSupportedDPWSVersions();
/*
* Check DPWS2009 aka DPWS1.1
*/
if (supportedVersions.contains(new Integer(DPWSConstants.DPWS_VERSION2009))) {
Message dpws1_1 = DPWS_UTIL.copyOutgoingMessage(message);
DPWS_UTIL.changeOutgoingMessage(DPWSConstants.DPWS_VERSION2009, dpws1_1);
dpws1_1.setProtocolInfo(new DPWSProtocolInfo(DPWSConstants.DPWS_VERSION2009));
sendUDPMulticast(dpws1_1, domain, callback);
}
/*
* Check DPWS2006
*/
if (supportedVersions.contains(new Integer(DPWSConstants2006.DPWS_VERSION2006))) {
Message dpws2006 = DPWS_UTIL.copyOutgoingMessage(message);
DPWS_UTIL.changeOutgoingMessage(DPWSConstants2006.DPWS_VERSION2006, dpws2006);
dpws2006.setProtocolInfo(new DPWSProtocolInfo(DPWSConstants2006.DPWS_VERSION2006));
sendUDPMulticast(dpws2006, domain, callback);
}
} else {
if (Log.isDebug()) {
Log.debug("Send " + message.getProtocolInfo().getDisplayName() + " Message", Log.DEBUG_LAYER_COMMUNICATION);
}
if (message.getProtocolInfo().getVersion() == DPWSConstants2006.DPWS_VERSION2006) {
DPWS_UTIL.changeOutgoingMessage(message.getProtocolInfo().getVersion(), message);
}
sendUDPMulticast(message, domain, callback);
}
}
/**
* @param message
* @param callback
* @param targetAddress
*/
protected void sendTCP(Message message, ResponseCallback callback, URI targetAddress) {
MessageReceiver receiver = callback == null ? GENERIC_RECEIVER : new SOAPResponseReceiver(message, callback);
HTTPRequest request = new SOAPRequest(targetAddress.getPath(), message, receiver);
if (DPWSFramework.hasModule(DPWSFramework.SECURITY_MODULE) && DPWSFramework.getSecurityManager().isHTTPS(targetAddress)) {
HTTPClient.exchange(new HTTPClientDestination(targetAddress, true, null), request);
} else {
HTTPClient.exchange(new HTTPClientDestination(targetAddress), request);
}
}
/**
* @param message
* @param domain
* @param callback
*/
protected void sendUDPMulticast(final Message message, final ProtocolDomain domain, final ResponseCallback callback) {
if (!(domain instanceof DPWSDomain)) {
return;
}
// remember outgoing message id in order to ignore it when we receive it
SENT_MULTICAST_MESSAGE_IDS.containsOrEnqueue(message.getMessageId());
final Waiter waiter = new Waiter();
final DPWSCommunicationManager myself = this;
// send without letting the caller wait
Runnable r = new Runnable() {
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
synchronized (waiter) {
waiter.pending = false;
waiter.notify();
}
DPWSDomain dpwsDomain = (DPWSDomain) domain;
IPAddress localHostAddress = dpwsDomain.getIPAddress();
// chose target address based on specified domain
int targetMulticastPort = DPWSConstants.DPWS_MCAST_PORT;
IPAddress targetMulticastAddress = localHostAddress.isIPv6() ? DPWSDiscoveryBinding.DPWS_MCAST_GROUP_IPv6 : DPWSDiscoveryBinding.DPWS_MCAST_GROUP_IPv4;
URI targetAdressURI = message.getTargetAddress();
if (targetAdressURI != null) {
targetMulticastAddress = new IPAddress(getCanonicalAddress(targetAdressURI.getHost()));
if (targetAdressURI.getPort() > 0) targetMulticastPort = targetAdressURI.getPort();
}
int messageType = message.getType();
if (messageType == DPWSMessageConstants.HELLO_MESSAGE || messageType == DPWSMessageConstants.PROBE_MATCHES_MESSAGE) {
try {
Thread.sleep(myself.getRandomApplicationDelay(message.getProtocolInfo().getVersion()));
} catch (InterruptedException e) {
// void
}
}
SOAPoverUDPClient client = null;
DPWSProtocolData protocolData = new DPWSProtocolData(dpwsDomain.getInterfaceName(), ProtocolData.DIRECTION_OUT, localHostAddress.getAddressWithoutNicId(), 0, targetMulticastAddress.getAddressWithoutNicId(), DPWSConstants.DPWS_MCAST_PORT, false);
try {
// make soap-over-udp clients reusable
synchronized (udpClientsPerDomain) {
client = (SOAPoverUDPClient) udpClientsPerDomain.get(dpwsDomain);
if (client == null || client.isClosed()) {
client = SOAPoverUDPClient.get(localHostAddress, 0, dpwsDomain.getInterfaceName());
udpClientsPerDomain.put(dpwsDomain, client);
}
}
if (callback != null && (messageType == DPWSMessageConstants.PROBE_MESSAGE || messageType == DPWSMessageConstants.RESOLVE_MESSAGE)) {
rrc.registerResponseCallback(message, callback, DispatchingProperties.getInstance().getMatchWaitTime());
}
client.send(targetMulticastAddress, targetMulticastPort, message, udpResponseHandler, protocolData);
MESSAGE_INFORMER.forwardMessage(message, protocolData);
// success!
} catch (IOException e) {
Log.warn("Could not multicast DPWS message to " + targetMulticastAddress + ":" + DPWSConstants.DPWS_MCAST_PORT + " over " + localHostAddress + ":" + protocolData.getSourcePort() + " due to an exception. Message: " + message + ", Exception: " + e.getMessage() + ", Callback: " + (callback == null ? "no callback" : callback.toString()));
// cleanup unusable client
try {
client.close();
} catch (IOException ex) {
Log.warn("Unable to close unusable UDP client");
}
synchronized (udpClientsPerDomain) {
udpClientsPerDomain.remove(dpwsDomain);
}
// Log.printStackTrace(e);
if (callback != null) {
callback.handleTransmissionException(message, e, protocolData);
}
}
// free-up on-stop-lock...
synchronized (udpTransmissionsLock) {
pendingUDPTransmissions--;
udpTransmissionsLock.notifyAll();
}
}
};
DPWSFramework.getThreadPool().execute(r);
/*
* make sure we return after actually having started the send
* procedure...
*/
synchronized (waiter) {
while (waiter.pending) {
try {
waiter.wait();
} catch (InterruptedException e) {
// ignore
}
}
}
}
private static class Waiter {
volatile boolean pending = true;
}
public void serializeMessageWithAttachments(Message message, String attachmentSep, List attachments, OutputStream out, ProtocolData pd) throws IOException {
/*
* For DPWS the "attachmentSep" is the MIME boundary.
*/
if (attachmentSep == null) {
SOAPMessageGeneratorFactory.getInstance().getMessage2SOAPGeneratorForCurrentThread().generateSOAPMessage(out, message, pd);
} else {
MIMEUtil.writeBoundary(out, attachmentSep.getBytes(), false, false);
MIMEBodyHeader mimeHeader = new MIMEBodyHeader();
mimeHeader.setHeaderField(MIMEConstants.MIME_HEADER_CONTENT_ID, MIMEConstants.PARAMETER_STARTVALUE);
mimeHeader.setHeaderField(MIMEConstants.MIME_HEADER_CONTENT_TYPE, InternetMediaType.getApplicationXOPXML().toString());
mimeHeader.setHeaderField(MIMEConstants.MIME_HEADER_CONTENT_TRANSFER_ENCODING, HTTPConstants.HTTP_HEADERVALUE_TRANSFERENCODING_BINARY);
mimeHeader.toStream(out);
SOAPMessageGeneratorFactory.getInstance().getMessage2SOAPGeneratorForCurrentThread().generateSOAPMessage(out, message, pd);
out.flush();
while (!attachments.isEmpty() && DPWSFramework.hasModule(DPWSFramework.ATTACHMENT_MODULE)) {
// attachments now implement MIMEEntity
Attachment response = (Attachment) attachments.remove(0);
mimeHeader = new MIMEBodyHeader();
mimeHeader.setHeaderField(MIMEConstants.MIME_HEADER_CONTENT_ID, response.getContentId());
try {
// if contentType is null set to "" to avoid
// NullPointerExceptions
String contentTypeString = "";
InternetMediaType contentType = response.getContentType();
if (contentType != null) {
contentTypeString = contentType.toString();
} else {
contentTypeString = InternetMediaType.getApplicationOctetStream().toString();
}
String transferEncoding = response.getTransferEncoding();
if (transferEncoding == null) {
transferEncoding = HTTPConstants.HTTP_HEADERVALUE_TRANSFERENCODING_BINARY;
}
mimeHeader.setHeaderField(MIMEConstants.MIME_HEADER_CONTENT_TYPE, contentTypeString);
mimeHeader.setHeaderField(MIMEConstants.MIME_HEADER_CONTENT_TRANSFER_ENCODING, transferEncoding);
} catch (AttachmentException e) {
/*
* shouldn't ever happen, as getContentType() or
* getTransferEncoding() shouldn't fail locally
*/
Log.printStackTrace(e);
}
MIMEUtil.writeBoundary(out, attachmentSep.getBytes(), false, false);
mimeHeader.toStream(out);
// flush the header. this allows the receiver to read the part
// send before.
out.flush();
try {
response.serialize(out);
} catch (AttachmentException e) {
throw new IOException(e.getMessage());
}
// this is needed for streaming support
out.flush();
}
MIMEUtil.writeBoundary(out, attachmentSep.getBytes(), false, true);
}
out.flush();
}
public ProtocolInfo getProtocolInfo() {
return new DPWSProtocolInfo();
}
public CommunicationUtil getCommunicationUtil() {
return DPWS_UTIL;
}
public ProtocolInfo createProtocolInfo(int version) {
return new DPWSProtocolInfo(version);
}
public HashSet getSupportedVersions() {
return DPWSProperties.getInstance().getSupportedDPWSVersions();
}
public boolean supportsAddressingNamespace(SOAPHeader header, String namespace, ProtocolData pd) throws VersionMismatchException {
if (WSAConstants.WSA_NAMESPACE_NAME.equals(namespace)) {
if (getSupportedVersions().contains(new Integer(DPWSConstants.DPWS_VERSION2009))) {
pd.setProtocolInfo(createProtocolInfo(DPWSConstants.DPWS_VERSION2009));
header.setProtocolInfo(pd.getProtocolInfo());
return true;
} else {
throw new VersionMismatchException("WS-Addressing: " + namespace + " is not supported in this Configuration", VersionMismatchException.TYPE_WRONG_ADDRESSING_VERSION);
}
} else if (WSAConstants2006.WSA_NAMESPACE_NAME.equals(namespace)) {
if (getSupportedVersions().contains(new Integer(DPWSConstants2006.DPWS_VERSION2006))) {
pd.setProtocolInfo(createProtocolInfo(DPWSConstants2006.DPWS_VERSION2006));
header.setProtocolInfo(pd.getProtocolInfo());
return true;
} else {
throw new VersionMismatchException("WS-Addressing: " + namespace + " is not supported in this Configuration", VersionMismatchException.TYPE_WRONG_ADDRESSING_VERSION);
}
}
return false;
}
public QNameSet getDeviceTypes() {
QNameSet dTypes = new QNameSet();
Iterator it = getSupportedVersions().iterator();
while (it.hasNext()) {
Integer version = (Integer) it.next();
int v = version.intValue();
switch (v) {
case DPWSConstants.DPWS_VERSION2009:
dTypes.add(DPWSConstants.DPWS_QN_DEVICETYPE);
break;
case DPWSConstants2006.DPWS_VERSION2006:
dTypes.add(DPWSConstants2006.DPWS_QN_DEVICETYPE);
break;
}
}
return dTypes;
}
}