/*******************************************************************************
* 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 org.ws4d.java.DPWSFramework;
import org.ws4d.java.communication.DPWS2006.DefaultDPWSCommunicatonUtil;
import org.ws4d.java.communication.connection.ip.IPAddress;
import org.ws4d.java.communication.monitor.MonitorStreamFactory;
import org.ws4d.java.communication.monitor.MonitoringContext;
import org.ws4d.java.communication.protocol.soap.generator.DefaultMessageDiscarder;
import org.ws4d.java.communication.protocol.soap.server.SOAPoverUDPServer.SOAPoverUDPDatagramHandler;
import org.ws4d.java.constants.DPWSMessageConstants;
import org.ws4d.java.dispatch.DeviceServiceRegistry;
import org.ws4d.java.dispatch.MessageInformer;
import org.ws4d.java.message.FaultMessage;
import org.ws4d.java.message.InvokeMessage;
import org.ws4d.java.message.Message;
import org.ws4d.java.message.MessageDiscarder;
import org.ws4d.java.message.SOAPException;
import org.ws4d.java.message.SOAPHeader;
import org.ws4d.java.message.discovery.ByeMessage;
import org.ws4d.java.message.discovery.HelloMessage;
import org.ws4d.java.message.discovery.ProbeMatchesMessage;
import org.ws4d.java.message.discovery.ProbeMessage;
import org.ws4d.java.message.discovery.ResolveMatchesMessage;
import org.ws4d.java.message.discovery.ResolveMessage;
import org.ws4d.java.message.eventing.GetStatusMessage;
import org.ws4d.java.message.eventing.GetStatusResponseMessage;
import org.ws4d.java.message.eventing.RenewMessage;
import org.ws4d.java.message.eventing.RenewResponseMessage;
import org.ws4d.java.message.eventing.SubscribeMessage;
import org.ws4d.java.message.eventing.SubscribeResponseMessage;
import org.ws4d.java.message.eventing.SubscriptionEndMessage;
import org.ws4d.java.message.eventing.UnsubscribeMessage;
import org.ws4d.java.message.eventing.UnsubscribeResponseMessage;
import org.ws4d.java.message.metadata.GetMessage;
import org.ws4d.java.message.metadata.GetMetadataMessage;
import org.ws4d.java.message.metadata.GetMetadataResponseMessage;
import org.ws4d.java.message.metadata.GetResponseMessage;
import org.ws4d.java.service.OperationDescription;
import org.ws4d.java.structures.HashSet;
import org.ws4d.java.structures.Iterator;
import org.ws4d.java.structures.MessageIdBuffer;
import org.ws4d.java.util.Log;
/**
*
*/
final class IncomingUDPReceiver extends SOAPoverUDPDatagramHandler {
private static final MessageInformer MESSAGE_INFORMER = MessageInformer.getInstance();
private final DefaultMessageDiscarder discarder = new RelevanceMessageDiscarder();
private final DefaultDPWSCommunicatonUtil util = DefaultDPWSCommunicatonUtil.getInstance();
private final HashSet helloListeners = new HashSet();
private final HashSet byeListeners = new HashSet();
private final HashSet probeResolveListeners = new HashSet();
/**
*
*/
IncomingUDPReceiver() {
super();
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.discovery.HelloMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public synchronized void receive(final HelloMessage hello, final ProtocolData protocolData) {
IncomingSOAPReceiver.markIncoming(hello);
if (!hello.getHeader().isValidated()) return;
if (!DeviceServiceRegistry.checkAndUpdateAppSequence(hello.getEndpointReference(), hello.getAppSequence())) {
if (Log.isDebug()) Log.debug("Discarding Hello message! Old AppSequence!", Log.DEBUG_LAYER_APPLICATION);
MonitorStreamFactory msf = DPWSFramework.getMonitorStreamFactory();
if (msf != null) {
MonitoringContext context = msf.getMonitoringContextIn(protocolData);
if (context != null) {
msf.discard(protocolData, context, MessageDiscarder.OLD_APPSEQUENCE);
} else {
Log.warn("Cannot get correct monitoring context for message generation.");
}
}
return;
}
boolean first = true;
for (Iterator it = helloListeners.iterator(); it.hasNext();) {
final IncomingMessageListener listener = (IncomingMessageListener) it.next();
final boolean final_first = first;
if (first) {
first = false;
}
Runnable r = new Runnable() {
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
listener.handle(hello, protocolData);
if (final_first) {
MESSAGE_INFORMER.forwardMessage(hello, protocolData);
}
}
};
DPWSFramework.getThreadPool().execute(r);
}
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.discovery.ByeMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public synchronized void receive(final ByeMessage bye, final ProtocolData protocolData) {
IncomingSOAPReceiver.markIncoming(bye);
if (!bye.getHeader().isValidated()) return;
if (!DeviceServiceRegistry.checkAndUpdateAppSequence(bye.getEndpointReference(), bye.getAppSequence())) {
if (Log.isDebug()) Log.debug("Discarding Hello message! Old AppSequence!", Log.DEBUG_LAYER_APPLICATION);
MonitorStreamFactory msf = DPWSFramework.getMonitorStreamFactory();
if (msf != null) {
MonitoringContext context = msf.getMonitoringContextIn(protocolData);
if (context != null) {
msf.discard(protocolData, context, MessageDiscarder.OLD_APPSEQUENCE);
} else {
Log.warn("Cannot get correct monitoring context for message generation.");
}
}
return;
}
boolean first = true;
for (Iterator it = byeListeners.iterator(); it.hasNext();) {
final IncomingMessageListener listener = (IncomingMessageListener) it.next();
final boolean final_first = first;
if (first) {
first = false;
}
Runnable r = new Runnable() {
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
listener.handle(bye, protocolData);
if (final_first) {
MESSAGE_INFORMER.forwardMessage(bye, protocolData);
}
}
};
DPWSFramework.getThreadPool().execute(r);
}
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.discovery.ProbeMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public synchronized void receive(final ProbeMessage probe, final ProtocolData protocolData) {
final long receiveTime = System.currentTimeMillis();
IncomingSOAPReceiver.markIncoming(probe);
boolean first = true;
for (Iterator it = probeResolveListeners.iterator(); it.hasNext();) {
final IncomingMessageListener receiver = (IncomingMessageListener) it.next();
final boolean final_first = first;
if (first) {
first = false;
}
Runnable r = new Runnable() {
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
ProtocolData pdOut = protocolData.createSwappedProtocolData();
try {
ProbeMatchesMessage probeMatches = receiver.handle(probe, protocolData);
if (final_first) {
MESSAGE_INFORMER.forwardMessage(probe, protocolData);
}
if (probeMatches != null) {
IncomingSOAPReceiver.markOutgoing(probeMatches);
// Check for Messageversion, if Version = 2006 the
// Namespaces and some attributs must be changed
util.changeOutgoingMessage(probeMatches.getProtocolInfo().getVersion(), probeMatches);
CommunicationManager comMan = DPWSFramework.getCommunicationManager(pdOut.getCommunicationManagerId());
// wait APP_MAX_DELAY before responding
long sendTime = receiveTime + comMan.getRandomApplicationDelay(probe.getProtocolInfo().getVersion());
long waitTime = sendTime - System.currentTimeMillis();
if (waitTime > 0) {
try {
Thread.sleep(waitTime);
} catch (InterruptedException e) {
// void
}
}
// respond with datagram to the given destination
respond(probeMatches, new IPAddress(pdOut.getDestinationHost()), pdOut.getDestinationPort(), pdOut);
MESSAGE_INFORMER.forwardMessage(probeMatches, pdOut);
}
} catch (SOAPException e) {
if (final_first) {
MESSAGE_INFORMER.forwardMessage(e.getFault(), pdOut);
}
}
}
};
DPWSFramework.getThreadPool().execute(r);
}
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.discovery.ProbeMatchesMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(ProbeMatchesMessage probeMatches, ProtocolData protocolData) {
receiveUnexpectedMessage(probeMatches, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.discovery.ResolveMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public synchronized void receive(final ResolveMessage resolve, final ProtocolData protocolData) {
IncomingSOAPReceiver.markIncoming(resolve);
boolean first = true;
for (Iterator it = probeResolveListeners.iterator(); it.hasNext();) {
final IncomingMessageListener receiver = (IncomingMessageListener) it.next();
final boolean final_first = first;
if (first) {
first = false;
}
Runnable r = new Runnable() {
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
ResolveMatchesMessage resolveMatches = receiver.handle(resolve, protocolData);
if (final_first) {
MESSAGE_INFORMER.forwardMessage(resolve, protocolData);
}
if (resolveMatches != null) {
IncomingSOAPReceiver.markOutgoing(resolveMatches);
// Check for Messageversion, if Version = 2006 the
// Namespaces and some attributs must be changed
util.changeOutgoingMessage(resolveMatches.getProtocolInfo().getVersion(), resolveMatches);
// respond with datagram to the given destination
respond(resolveMatches, new IPAddress(protocolData.getDestinationHost()), protocolData.getDestinationPort(), protocolData);
MESSAGE_INFORMER.forwardMessage(resolveMatches, protocolData);
}
}
};
DPWSFramework.getThreadPool().execute(r);
}
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.discovery.ResolveMatchesMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(ResolveMatchesMessage resolveMatches, ProtocolData protocolData) {
receiveUnexpectedMessage(resolveMatches, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.metadata.GetMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(GetMessage get, ProtocolData protocolData) {
receiveUnexpectedMessage(get, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.metadata.GetResponseMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(GetResponseMessage getResponse, ProtocolData protocolData) {
receiveUnexpectedMessage(getResponse, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.metadata.GetMetadataMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(GetMetadataMessage getMetadata, ProtocolData protocolData) {
receiveUnexpectedMessage(getMetadata, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.metadata. GetMetadataResponseMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(GetMetadataResponseMessage getMetadataResponse, ProtocolData protocolData) {
receiveUnexpectedMessage(getMetadataResponse, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.eventing.SubscribeMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(SubscribeMessage subscribe, ProtocolData protocolData) {
receiveUnexpectedMessage(subscribe, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.eventing.SubscribeResponseMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(SubscribeResponseMessage subscribeResponse, ProtocolData protocolData) {
receiveUnexpectedMessage(subscribeResponse, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.eventing.GetStatusMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(GetStatusMessage getStatus, ProtocolData protocolData) {
receiveUnexpectedMessage(getStatus, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.eventing.GetStatusResponseMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(GetStatusResponseMessage getStatusResponse, ProtocolData protocolData) {
receiveUnexpectedMessage(getStatusResponse, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.eventing.RenewMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(RenewMessage renew, ProtocolData protocolData) {
receiveUnexpectedMessage(renew, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.eventing.RenewResponseMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(RenewResponseMessage renewResponse, ProtocolData protocolData) {
receiveUnexpectedMessage(renewResponse, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.eventing.UnsubscribeMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(UnsubscribeMessage unsubscribe, ProtocolData protocolData) {
receiveUnexpectedMessage(unsubscribe, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.eventing.UnsubscribeResponseMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(UnsubscribeResponseMessage unsubscribeResponse, ProtocolData protocolData) {
receiveUnexpectedMessage(unsubscribeResponse, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.eventing.SubscriptionEndMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(SubscriptionEndMessage subscriptionEnd, ProtocolData protocolData) {
receiveUnexpectedMessage(subscriptionEnd, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.invocation.InvokeMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(InvokeMessage invoke, ProtocolData protocolData) {
receiveUnexpectedMessage(invoke, protocolData);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#receive
* (org.ws4d.java.message.FaultMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public void receive(FaultMessage fault, ProtocolData protocolData) {
receiveUnexpectedMessage(fault, protocolData);
}
/*
* (non-Javadoc)
* @see org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#
* receiveFailed(java.lang.Exception,
* org.ws4d.java.communication.ProtocolData)
*/
public void receiveFailed(Exception e, ProtocolData protocolData) {
/*
* who cares?? :-P this exception gets logged from within the SOAP 2
* message generator
*/
}
/*
* (non-Javadoc)
* @see org.ws4d.java.communication.protocol.soap.generator.MessageReceiver#
* sendFailed(java.lang.Exception, org.ws4d.java.communication.ProtocolData)
*/
public void sendFailed(Exception e, ProtocolData protocolData) {
/*
* we are on the server side, thus we don't send anything that could go
* wrong
*/
}
/*
* (non-Javadoc)
* @see org.ws4d.java.communication.protocol.soap.server.SOAPoverUDPServer.
* SOAPoverUDPDatagramHandler#getDiscarder()
*/
protected DefaultMessageDiscarder getDiscarder() {
return discarder;
}
synchronized void registerHelloListener(IncomingMessageListener listener) {
helloListeners.add(listener);
}
synchronized void registerByeListener(IncomingMessageListener listener) {
byeListeners.add(listener);
}
synchronized void registerProbeResolveListener(IncomingMessageListener listener) {
probeResolveListeners.add(listener);
}
synchronized void unregisterHelloListener(IncomingMessageListener listener) {
helloListeners.remove(listener);
}
synchronized void unregisterByeListener(IncomingMessageListener listener) {
byeListeners.remove(listener);
}
synchronized void unregisterProbeResolveListener(IncomingMessageListener listener) {
probeResolveListeners.remove(listener);
}
synchronized void register(int[] messageTypes, IncomingMessageListener listener) {
for (int i = 0; i < messageTypes.length; i++) {
switch (messageTypes[i]) {
case (DPWSMessageConstants.HELLO_MESSAGE): {
helloListeners.add(listener);
break;
}
case (DPWSMessageConstants.BYE_MESSAGE): {
byeListeners.add(listener);
break;
}
case (DPWSMessageConstants.PROBE_MESSAGE): {
probeResolveListeners.add(listener);
break;
}
case (DPWSMessageConstants.RESOLVE_MESSAGE): {
probeResolveListeners.add(listener);
break;
}
}
}
}
synchronized void unregister(int[] messageTypes, IncomingMessageListener listener) {
for (int i = 0; i < messageTypes.length; i++) {
switch (messageTypes[i]) {
case (DPWSMessageConstants.HELLO_MESSAGE): {
helloListeners.remove(listener);
break;
}
case (DPWSMessageConstants.BYE_MESSAGE): {
byeListeners.remove(listener);
break;
}
case (DPWSMessageConstants.PROBE_MESSAGE): {
probeResolveListeners.remove(listener);
break;
}
case (DPWSMessageConstants.RESOLVE_MESSAGE): {
probeResolveListeners.remove(listener);
break;
}
}
}
}
synchronized boolean isEmpty() {
return helloListeners.isEmpty() && byeListeners.isEmpty() && probeResolveListeners.isEmpty();
}
synchronized void clear() {
helloListeners.clear();
byeListeners.clear();
probeResolveListeners.clear();
}
private void receiveUnexpectedMessage(Message message, ProtocolData protocolData) {
IncomingSOAPReceiver.markIncoming(message);
String actionName = message.getAction().toString();
Log.error("<I> Unexpected multicast SOAP-over-UDP message: " + actionName);
if (Log.isDebug()) {
Log.error(message.toString());
}
MESSAGE_INFORMER.forwardMessage(message, protocolData);
}
public OperationDescription getOperation(String action) {
return null;
}
private class RelevanceMessageDiscarder extends DefaultMessageDiscarder {
private final MessageIdBuffer duplicateMessageIds = new MessageIdBuffer();
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.soap.generator.MessageDiscarder
* #discardMessage(org.ws4d.java.message.SOAPHeader,
* org.ws4d.java.communication.ProtocolData)
*/
public int discardMessage(SOAPHeader header, ProtocolData protocolData) {
int superResult = super.discardMessage(header, protocolData);
if (superResult != NOT_DISCARDED) return superResult;
if (duplicateMessageIds.containsOrEnqueue(header.getMessageId())) {
return DUPLICATE_MESSAGE;
}
synchronized (IncomingUDPReceiver.this) {
int msgType = header.getDPWSMessageType();
switch (msgType) {
case DPWSMessageConstants.HELLO_MESSAGE:
if (helloListeners.isEmpty()) return NOT_RELEVANT_MESSAGE;
break;
case DPWSMessageConstants.BYE_MESSAGE:
if (byeListeners.isEmpty()) return NOT_RELEVANT_MESSAGE;
break;
case DPWSMessageConstants.PROBE_MESSAGE:
if (probeResolveListeners.isEmpty()) return NOT_RELEVANT_MESSAGE;
break;
case DPWSMessageConstants.RESOLVE_MESSAGE:
if (probeResolveListeners.isEmpty()) return NOT_RELEVANT_MESSAGE;
break;
default:
return NOT_RELEVANT_MESSAGE;
}
}
return NOT_DISCARDED;
}
}
}