use of org.eclipse.milo.opcua.stack.core.types.structured.PublishResponse in project milo by eclipse.
the class Subscription method returnKeepAlive.
private void returnKeepAlive(ServiceRequest service) {
ResponseHeader header = service.createResponseHeader();
UInteger sequenceNumber = uint(currentSequenceNumber());
NotificationMessage notificationMessage = new NotificationMessage(sequenceNumber, DateTime.now(), new ExtensionObject[0]);
UInteger[] available = getAvailableSequenceNumbers();
StatusCode[] acknowledgeResults = service.attr(KEY_ACK_RESULTS).get();
PublishResponse response = new PublishResponse(header, subscriptionId, available, moreNotifications, notificationMessage, acknowledgeResults, new DiagnosticInfo[0]);
service.setResponse(response);
logger.debug("[id={}] returned keep-alive NotificationMessage sequenceNumber={}.", subscriptionId, sequenceNumber);
}
use of org.eclipse.milo.opcua.stack.core.types.structured.PublishResponse in project milo by eclipse.
the class OpcUaSubscriptionManager method onPublishComplete.
private void onPublishComplete(PublishResponse response, AtomicLong pendingCount) {
logger.debug("onPublishComplete() response for subscriptionId={}", response.getSubscriptionId());
UInteger subscriptionId = response.getSubscriptionId();
OpcUaSubscription subscription = subscriptions.get(subscriptionId);
if (subscription == null) {
WatchdogTimer watchdogTimer = watchdogTimers.remove(subscriptionId);
if (watchdogTimer != null)
watchdogTimer.cancel();
pendingCount.getAndUpdate(p -> (p > 0) ? p - 1 : 0);
maybeSendPublishRequests();
return;
}
WatchdogTimer watchdogTimer = watchdogTimers.get(subscriptionId);
if (watchdogTimer != null)
watchdogTimer.kick();
NotificationMessage notificationMessage = response.getNotificationMessage();
long sequenceNumber = notificationMessage.getSequenceNumber().longValue();
long expectedSequenceNumber = subscription.getLastSequenceNumber() + 1;
if (sequenceNumber > expectedSequenceNumber) {
logger.warn("[id={}] expected sequence={}, received sequence={}. Calling Republish service...", subscriptionId, expectedSequenceNumber, sequenceNumber);
processingQueue.pause();
processingQueue.submitToHead(() -> onPublishComplete(response, pendingCount));
republish(subscriptionId, expectedSequenceNumber, sequenceNumber).whenComplete((dataLost, ex) -> {
if (ex != null) {
logger.debug("Republish failed: {}", ex.getMessage(), ex);
subscriptionListeners.forEach(l -> l.onNotificationDataLost(subscription));
subscription.getNotificationListeners().forEach(l -> l.onNotificationDataLost(subscription));
} else {
// Republish succeeded, possibly with some data loss, resume processing.
if (dataLost) {
subscriptionListeners.forEach(l -> l.onNotificationDataLost(subscription));
subscription.getNotificationListeners().forEach(l -> l.onNotificationDataLost(subscription));
}
}
subscription.setLastSequenceNumber(sequenceNumber - 1);
processingQueue.resume();
});
return;
}
if (notificationMessage.getNotificationData() != null && notificationMessage.getNotificationData().length > 0) {
// Set last sequence number only if this isn't a keep-alive
subscription.setLastSequenceNumber(sequenceNumber);
}
UInteger[] availableSequenceNumbers = response.getAvailableSequenceNumbers();
synchronized (subscription.availableAcknowledgements) {
subscription.availableAcknowledgements.clear();
if (availableSequenceNumbers != null && availableSequenceNumbers.length > 0) {
Collections.addAll(subscription.availableAcknowledgements, availableSequenceNumbers);
}
}
if (logger.isDebugEnabled() && availableSequenceNumbers != null) {
String[] seqStrings = Arrays.stream(availableSequenceNumbers).map(sequence -> String.format("id=%s/seq=%s", subscriptionId, sequence)).toArray(String[]::new);
logger.debug("[id={}] PublishResponse sequence={}, available sequences={}", subscriptionId, sequenceNumber, Arrays.toString(seqStrings));
}
DateTime publishTime = notificationMessage.getPublishTime();
logger.debug("onPublishComplete(), subscriptionId={}, sequenceNumber={}, publishTime={}", subscriptionId, notificationMessage.getSequenceNumber(), publishTime);
deliverNotificationMessage(subscription, notificationMessage).thenRunAsync(() -> {
pendingCount.getAndUpdate(p -> (p > 0) ? p - 1 : 0);
maybeSendPublishRequests();
}, client.getConfig().getExecutor());
}
use of org.eclipse.milo.opcua.stack.core.types.structured.PublishResponse in project milo by eclipse.
the class Subscription method sendNotifications.
private void sendNotifications(ServiceRequest service, List<UaStructure> notifications) {
List<MonitoredItemNotification> dataNotifications = Lists.newArrayList();
List<EventFieldList> eventNotifications = Lists.newArrayList();
notifications.forEach(notification -> {
if (notification instanceof MonitoredItemNotification) {
dataNotifications.add((MonitoredItemNotification) notification);
} else if (notification instanceof EventFieldList) {
eventNotifications.add((EventFieldList) notification);
}
});
List<ExtensionObject> notificationData = Lists.newArrayList();
if (dataNotifications.size() > 0) {
DataChangeNotification dataChange = new DataChangeNotification(dataNotifications.toArray(new MonitoredItemNotification[0]), new DiagnosticInfo[0]);
notificationData.add(ExtensionObject.encode(serializationContext, dataChange, dataChange.getBinaryEncodingId(), OpcUaDefaultBinaryEncoding.getInstance()));
subscriptionDiagnostics.getDataChangeNotificationsCount().add(dataNotifications.size());
}
if (eventNotifications.size() > 0) {
EventNotificationList eventChange = new EventNotificationList(eventNotifications.toArray(new EventFieldList[0]));
notificationData.add(ExtensionObject.encode(serializationContext, eventChange, eventChange.getBinaryEncodingId(), OpcUaDefaultBinaryEncoding.getInstance()));
subscriptionDiagnostics.getEventNotificationsCount().add(eventNotifications.size());
}
subscriptionDiagnostics.getNotificationsCount().add(notificationData.size());
UInteger sequenceNumber = uint(nextSequenceNumber());
NotificationMessage notificationMessage = new NotificationMessage(sequenceNumber, DateTime.now(), notificationData.toArray(new ExtensionObject[0]));
availableMessages.put(notificationMessage.getSequenceNumber(), notificationMessage);
while (availableMessages.size() > MAX_AVAILABLE_MESSAGES) {
Map.Entry<UInteger, NotificationMessage> entry = availableMessages.pollFirstEntry();
if (entry != null) {
subscriptionDiagnostics.getDiscardedMessageCount().increment();
logger.debug("Discarded cached NotificationMessage with sequenceNumber={}", entry.getKey());
}
}
UInteger[] available = getAvailableSequenceNumbers();
StatusCode[] acknowledgeResults = service.attr(KEY_ACK_RESULTS).get();
ResponseHeader header = service.createResponseHeader();
PublishResponse response = new PublishResponse(header, subscriptionId, available, moreNotifications, notificationMessage, acknowledgeResults, new DiagnosticInfo[0]);
service.setResponse(response);
logger.debug("[id={}] returning {} DataChangeNotification(s) and " + "{} EventNotificationList(s) sequenceNumber={} moreNotifications={}.", subscriptionId, dataNotifications.size(), eventNotifications.size(), sequenceNumber, moreNotifications);
}
use of org.eclipse.milo.opcua.stack.core.types.structured.PublishResponse in project milo by eclipse.
the class Subscription method returnStatusChangeNotification.
void returnStatusChangeNotification(ServiceRequest service, StatusCode status) {
StatusChangeNotification statusChange = new StatusChangeNotification(status, null);
UInteger sequenceNumber = uint(nextSequenceNumber());
NotificationMessage notificationMessage = new NotificationMessage(sequenceNumber, DateTime.now(), new ExtensionObject[] { ExtensionObject.encode(serializationContext, statusChange) });
ResponseHeader header = service.createResponseHeader();
PublishResponse response = new PublishResponse(header, subscriptionId, new UInteger[0], false, notificationMessage, service.attr(KEY_ACK_RESULTS).get(), new DiagnosticInfo[0]);
service.setResponse(response);
logger.debug("[id={}] returned StatusChangeNotification ({}) sequenceNumber={}.", subscriptionId, status, sequenceNumber);
}
use of org.eclipse.milo.opcua.stack.core.types.structured.PublishResponse in project milo by eclipse.
the class OpcUaSubscriptionManager method sendPublishRequest.
private void sendPublishRequest(UaSession session, AtomicLong pendingCount) {
List<SubscriptionAcknowledgement> subscriptionAcknowledgements = new ArrayList<>();
subscriptions.values().forEach(subscription -> {
synchronized (subscription.availableAcknowledgements) {
subscription.availableAcknowledgements.forEach(sequenceNumber -> subscriptionAcknowledgements.add(new SubscriptionAcknowledgement(subscription.getSubscriptionId(), sequenceNumber)));
subscription.availableAcknowledgements.clear();
}
});
RequestHeader requestHeader = client.getStackClient().newRequestHeader(session.getAuthenticationToken(), getTimeoutHint());
UInteger requestHandle = requestHeader.getRequestHandle();
PublishRequest request = new PublishRequest(requestHeader, subscriptionAcknowledgements.toArray(new SubscriptionAcknowledgement[0]));
if (logger.isDebugEnabled()) {
String[] ackStrings = subscriptionAcknowledgements.stream().map(ack -> String.format("id=%s/seq=%s", ack.getSubscriptionId(), ack.getSequenceNumber())).toArray(String[]::new);
logger.debug("Sending PublishRequest, requestHandle={}, acknowledgements={}", requestHandle, Arrays.toString(ackStrings));
}
client.<PublishResponse>sendRequest(request).whenComplete((response, ex) -> {
if (response != null) {
logger.debug("Received PublishResponse, sequenceNumber={}", response.getNotificationMessage().getSequenceNumber());
processingQueue.submit(() -> onPublishComplete(response, pendingCount));
} else {
StatusCode statusCode = UaException.extract(ex).map(UaException::getStatusCode).orElse(StatusCode.BAD);
logger.debug("Publish service failure (requestHandle={}): {}", requestHandle, statusCode, ex);
pendingCount.getAndUpdate(p -> (p > 0) ? p - 1 : 0);
if (statusCode.getValue() != StatusCodes.Bad_NoSubscription && statusCode.getValue() != StatusCodes.Bad_TooManyPublishRequests) {
maybeSendPublishRequests();
}
UaException uax = UaException.extract(ex).orElse(new UaException(ex));
subscriptionListeners.forEach(l -> l.onPublishFailure(uax));
}
});
}
Aggregations