package org.ws4d.java.dispatch; import org.ws4d.java.communication.CommunicationManager; import org.ws4d.java.communication.DefaultResponseCallback; import org.ws4d.java.communication.Discovery; import org.ws4d.java.communication.ProtocolData; import org.ws4d.java.communication.ProtocolInfo; import org.ws4d.java.communication.TimeoutException; import org.ws4d.java.constants.DPWSMessageConstants; import org.ws4d.java.dispatch.DefaultServiceReference.GetMetadataRequestSynchronizer; import org.ws4d.java.dispatch.DefaultServiceReference.RequestSynchronizer; import org.ws4d.java.dispatch.DefaultServiceReference.ResolveRequestSynchronizer; import org.ws4d.java.message.FaultMessage; import org.ws4d.java.message.Message; import org.ws4d.java.message.discovery.ResolveMatch; import org.ws4d.java.message.discovery.ResolveMatchesMessage; import org.ws4d.java.message.discovery.ResolveMessage; import org.ws4d.java.message.metadata.GetMetadataMessage; import org.ws4d.java.message.metadata.GetMetadataResponseMessage; import org.ws4d.java.service.Service; import org.ws4d.java.service.reference.Reference; import org.ws4d.java.structures.ArrayList; import org.ws4d.java.structures.Iterator; import org.ws4d.java.types.EndpointReference; import org.ws4d.java.types.EprInfo; import org.ws4d.java.types.HostedMData; import org.ws4d.java.types.URI; import org.ws4d.java.types.XAddressInfo; import org.ws4d.java.types.XAddressInfoSet; import org.ws4d.java.util.Log; public class DefaultServiceReferenceCallback extends DefaultResponseCallback { protected final DefaultServiceReference servRef; /** * @param servRef */ public DefaultServiceReferenceCallback(DefaultServiceReference servRef, XAddressInfo targetXAddressInfo) { super(targetXAddressInfo); this.servRef = servRef; } /* * (non-Javadoc) * @see * org.ws4d.java.communication.DefaultResponseCallback#handle(org.ws4d.java * .message.Message, org.ws4d.java.message.discovery.ResolveMatchesMessage, * org.ws4d.java.communication.ProtocolData) */ public void handle(Message request, ResolveMatchesMessage resolveMatches, ProtocolData protocolData) { ResolveRequestSynchronizer sync = null; try { synchronized (servRef) { sync = (ResolveRequestSynchronizer) servRef.synchronizers.remove(request.getMessageId()); if (sync == null) { /* * this shouldn't ever happen, as it would mean we receive a * response to a request we never sent... */ Log.warn("Ignoring unexpected ResolveMatches message " + resolveMatches); return; } if (sync.hostedBlockVersion == servRef.hostedBlockVersion) { XAddressInfo targetXAddressInfo = getTargetAddress(); if (targetXAddressInfo != null) { targetXAddressInfo.mergeProtocolInfo(protocolData.getProtocolInfo()); } ResolveMatch match = resolveMatches.getResolveMatch(); XAddressInfoSet xAddresses = match.getXAddressInfoSet(); if (xAddresses != null) { EndpointReference epr = match.getEndpointReference(); String comManId = protocolData.getCommunicationManagerId(); OUTER: for (Iterator it = xAddresses.iterator(); it.hasNext();) { XAddressInfo xAdrInfo = (XAddressInfo) it.next(); URI address = xAdrInfo.getXAddress(); if (servRef.resolvedEprInfos == null) { servRef.resolvedEprInfos = new ArrayList(xAddresses.size()); while (true) { if (protocolData.sourceMatches(address)) { servRef.resolvedEprInfos.add(0, new EprInfo(epr, address, comManId, protocolData.getProtocolInfo())); } else { servRef.resolvedEprInfos.add(new EprInfo(epr, address, comManId, protocolData.getProtocolInfo())); } if (!it.hasNext()) { break; } xAdrInfo = (XAddressInfo) it.next(); address = xAdrInfo.getXAddress(); } servRef.currentXAddressIndex = -1; break; } for (Iterator it2 = servRef.resolvedEprInfos.iterator(); it2.hasNext();) { EprInfo oldInfo = (EprInfo) it2.next(); if (oldInfo.getXAddress().equals(address)) { continue OUTER; } } if (protocolData.sourceMatches(address)) { servRef.resolvedEprInfos.add(servRef.currentXAddressIndex, new EprInfo(epr, address, comManId, protocolData.getProtocolInfo())); } else { servRef.resolvedEprInfos.add(new EprInfo(epr, address, comManId, protocolData.getProtocolInfo())); } } if (servRef.resolvedEprInfos == null || servRef.currentXAddressIndex >= servRef.resolvedEprInfos.size() - 1) { if (maybeSendNextResolve(sync, protocolData.getProtocolInfo())) { return; } } else { sync.xAddress = servRef.preferredXAddressInfo = (EprInfo) servRef.resolvedEprInfos.get(++servRef.currentXAddressIndex); } } } else { if (Log.isDebug()) { Log.debug("Concurrent service update detected.", Log.DEBUG_LAYER_FRAMEWORK); } } if (sync == servRef.resolveSynchronizer) { servRef.resolveSynchronizer = null; } } } catch (Throwable e) { sync.exception = new TimeoutException("Unexpected exception during resolve matches processing: " + e); } synchronized (sync) { sync.pending = false; sync.notifyAll(); } } private boolean maybeSendNextResolve(ResolveRequestSynchronizer sync, ProtocolInfo version) { if (servRef.unresolvedEPRs != null && servRef.unresolvedEPRs.size() > 0) { EndpointReference eprToResolve = (EndpointReference) servRef.unresolvedEPRs.remove(0); ResolveMessage resolve = new ResolveMessage(CommunicationManager.ID_NULL); servRef.synchronizers.put(resolve.getMessageId(), sync); resolve.setProtocolInfo(version); resolve.setEndpointReference(eprToResolve); OutDispatcher.getInstance().send(resolve, null, Discovery.getDefaultOutputDomains(), this); /* * don't wake up waiters as result will come in later */ return true; } else { sync.exception = new TimeoutException("No more options to obtain transport address for service."); } return false; } /* * (non-Javadoc) * @see * org.ws4d.java.communication.DefaultResponseCallback#handle(org.ws4d.java * .message.Message, * org.ws4d.java.message.metadata.GetMetadataResponseMessage, * org.ws4d.java.communication.ProtocolData) */ public void handle(Message request, GetMetadataResponseMessage response, ProtocolData protocolData) { GetMetadataRequestSynchronizer sync = null; try { synchronized (servRef) { if (servRef.getLocation() == Reference.LOCATION_LOCAL) { Log.error("Received GetMetadataResponse message for a local reference"); return; } servRef.setLocation(Reference.LOCATION_REMOTE); sync = (GetMetadataRequestSynchronizer) servRef.synchronizers.remove(request.getMessageId()); if (sync == null) { /* * this shouldn't ever happen, as it would mean we receive a * response to a request we never sent... */ Log.warn("Ignoring unexpected GetMetadataResponse message " + response); return; } if (sync.hostedBlockVersion == servRef.hostedBlockVersion) { getTargetAddress().mergeProtocolInfo(protocolData.getProtocolInfo()); /* * set parent device ref */ if (response.getHost() != null) { EndpointReference devEpr = response.getHost().getEndpointReference(); if (devEpr != null) { servRef.setParentDeviceReference(DeviceServiceRegistry.getDeviceReference(devEpr)); } } /* * update metadataReferences */ servRef.setMetadataReferences(response.getMetadataReferences()); /* * update metadata locations */ servRef.setMetaDataLocations(response.getMetadataLocations()); /* * update WSDLs */ servRef.setWSDLs(response.getWSDLs()); HostedMData newHosted = response.getHosted(request.getTo()); if (newHosted == null) { Service service = servRef.createProxyServiceFromLocalMetadata(); if (service == null) { sync.exception = new TimeoutException("No Hosted block within GetMetadataResponse: " + response); } else { sync.service = service; Log.warn("Proxy service created from local metadata because no Hosted block was found within GetMetadataResponse: " + response); } } else { DeviceServiceRegistry.updateServiceReferenceRegistration(newHosted, servRef); // Do this before creating / updating proxy service servRef.setHostedFromService(newHosted, protocolData.getCommunicationManagerId(), protocolData); /* * update / create proxy service, inform service * listener */ try { servRef.checkAndUpdateService(protocolData); } catch (MissingMetadataException e) { sync.exception = new TimeoutException("Unable to create service proxy: " + e); } } } else { if (Log.isDebug()) { Log.debug("Concurrent service update detected, rebuilding service proxy", Log.DEBUG_LAYER_FRAMEWORK); } } } } catch (Throwable e) { e.printStackTrace(); sync.exception = new TimeoutException("Unexpected exception during get metadata response processing: " + e); } synchronized (sync) { sync.pending = false; sync.notifyAll(); } } /* * (non-Javadoc) * @see * org.ws4d.java.communication.DefaultResponseCallback#handle(org.ws4d.java * .message.Message, org.ws4d.java.message.FaultMessage, * org.ws4d.java.communication.ProtocolData) */ public void handle(Message request, FaultMessage fault, ProtocolData protocolData) { if (request.getType() != DPWSMessageConstants.GET_METADATA_MESSAGE) { Log.warn("DefaultDeviceReferenceCallback.handle(FaultMessage): unexpected fault message " + fault + ", request was " + request); return; } RequestSynchronizer sync = null; boolean doResend = false; try { synchronized (servRef) { sync = (RequestSynchronizer) servRef.synchronizers.get(request.getMessageId()); if (sync == null) { Log.warn("No synchronizer found for request message " + request); return; } getTargetAddress().mergeProtocolInfo(protocolData.getProtocolInfo()); Log.error("Get metadata request leads to fault message: " + fault); doResend = sync.hostedBlockVersion == servRef.hostedBlockVersion; if (!doResend) { servRef.synchronizers.remove(request.getMessageId()); } } if (doResend) { XAddressInfo xAddressInfo = servRef.getNextXAddressInfoAfterFailure(request.getTargetAddress()); request.setTargetXAddressInfo(xAddressInfo); OutDispatcher.getInstance().send((GetMetadataMessage) request, xAddressInfo, this); } else { sync.exception = new TimeoutException("Get metadata request leads to fault message: " + fault); } } catch (Throwable e) { sync.exception = new TimeoutException("Exception occured during fault processing: " + e); } synchronized (sync) { sync.pending = false; sync.notifyAll(); } } /* * (non-Javadoc) * @see * org.ws4d.java.communication.ResponseCallback#handleMalformedResponseException * (org.ws4d.java.message.Message, java.lang.Exception, * org.ws4d.java.communication.ProtocolData) */ public void handleMalformedResponseException(Message request, Exception exception, ProtocolData protocolData) { if (causedByResolve(request)) { return; } if (request.getType() != DPWSMessageConstants.GET_METADATA_MESSAGE) { Log.warn("Unexpected malformed response, request was " + request); /* * We could "return;" here, but for DPWS2006 GET is send for devices * and services, so we MUST check it .... */ } RequestSynchronizer sync = null; boolean doResend = false; try { synchronized (servRef) { sync = (RequestSynchronizer) servRef.synchronizers.get(request.getMessageId()); if (sync == null) { Log.warn("No synchronizer found for request message " + request); return; } Log.error("Get metadata request leads to an exception: " + exception); doResend = sync.hostedBlockVersion == servRef.hostedBlockVersion; if (!doResend) { servRef.synchronizers.remove(request.getMessageId()); } } if (doResend) { XAddressInfo xAddressInfo = servRef.getNextXAddressInfoAfterFailure(request.getTargetAddress()); request.setTargetXAddressInfo(xAddressInfo); OutDispatcher.getInstance().send((GetMetadataMessage) request, xAddressInfo, this); } else { sync.exception = new TimeoutException("Get metadata request leads to an exception: " + exception); } } catch (Throwable e) { if (sync instanceof GetMetadataRequestSynchronizer) { GetMetadataRequestSynchronizer gmsync = (GetMetadataRequestSynchronizer) sync; Service service = servRef.createProxyServiceFromLocalMetadata(); if (service != null) { gmsync.service = service; } else { sync.exception = new TimeoutException("Exception occured during malformed response processing: " + e); } } else { sync.exception = new TimeoutException("Exception occured during malformed response processing: " + e); } } synchronized (sync) { sync.pending = false; sync.notifyAll(); } } /* * (non-Javadoc) * @see org.ws4d.java.communication.DefaultResponseCallback# * handleTransmissionException(org.ws4d.java.message.Message, * java.lang.Exception, org.ws4d.java.communication.ProtocolData) */ public void handleTransmissionException(Message request, Exception exception, ProtocolData protocolData) { if (causedByResolve(request)) { return; } if (request.getType() != DPWSMessageConstants.GET_METADATA_MESSAGE) { Log.warn("Unexpected transmission exception, request was " + request); return; } RequestSynchronizer sync = null; boolean doResend = false; try { synchronized (servRef) { sync = (RequestSynchronizer) servRef.synchronizers.get(request.getMessageId()); if (sync == null) { Log.warn("No synchronizer found for request message " + request); return; } Log.error("Get metadata request leads to transmission exception: " + exception); doResend = sync.hostedBlockVersion == servRef.hostedBlockVersion; if (!doResend) { servRef.synchronizers.remove(request.getMessageId()); } } if (doResend) { XAddressInfo xAddressInfo = servRef.getNextXAddressInfoAfterFailure(request.getTargetAddress()); request.setTargetXAddressInfo(xAddressInfo); OutDispatcher.getInstance().send((GetMetadataMessage) request, xAddressInfo, this); } else { sync.exception = new TimeoutException("Get metadata request leads to transmission exception: " + exception); } } catch (Throwable e) { sync.exception = new TimeoutException("Exception occured during transmission exception processing: " + e); } synchronized (sync) { sync.pending = false; sync.notifyAll(); } } /* * (non-Javadoc) * @see * org.ws4d.java.communication.DefaultResponseCallback#handleTimeout(org * .ws4d.java.message.Message) */ public void handleTimeout(Message request) { if (causedByResolve(request)) { return; } if (request.getType() != DPWSMessageConstants.GET_METADATA_MESSAGE) { Log.warn("Unexpected timeout, request was " + request); return; } RequestSynchronizer sync = null; boolean doResend = false; try { synchronized (servRef) { sync = (RequestSynchronizer) servRef.synchronizers.get(request.getMessageId()); if (sync == null) { Log.warn("No synchronizer found for request message " + request); return; } Log.error("Get metadata request timeout."); doResend = sync.hostedBlockVersion == servRef.hostedBlockVersion; if (!doResend) { servRef.synchronizers.remove(request.getMessageId()); } } if (doResend) { XAddressInfo xAddressInfo = servRef.getNextXAddressInfoAfterFailure(request.getTargetAddress()); request.setTargetXAddressInfo(xAddressInfo); OutDispatcher.getInstance().send((GetMetadataMessage) request, xAddressInfo, this); } else { sync.exception = new TimeoutException("Get metadata request timeout."); } } catch (Throwable e) { sync.exception = new TimeoutException("Exception occured during timeout processing: " + e); } synchronized (sync) { sync.pending = false; sync.notifyAll(); } } private boolean causedByResolve(Message request) { if (request.getType() == DPWSMessageConstants.RESOLVE_MESSAGE) { ResolveRequestSynchronizer sync; synchronized (servRef) { sync = (ResolveRequestSynchronizer) servRef.synchronizers.get(request.getMessageId()); if (sync == null) { /* * this usually occurs when a resolve request times out * after a valid resolve matches has been received; we may * ignore this silently */ /* * this shouldn't ever happen, as it would mean we receive a * response to a request we never sent... */ // Log.warn("DefaultDeviceReferenceCallback: ignoring unexpected ResolveMatches message " // + request); return true; } if (sync.hostedBlockVersion == servRef.hostedBlockVersion) { if (maybeSendNextResolve(sync, request.getProtocolInfo())) { return true; } } if (sync == servRef.resolveSynchronizer) { servRef.resolveSynchronizer = null; } } synchronized (sync) { sync.pending = false; sync.notifyAll(); } return true; } return false; } }