Skip to content

Server Events

Kevin Herron edited this page Oct 5, 2026 · 11 revisions

Create event field values and route them to subscriptions monitoring the appropriate source.

Milo 1.2.0-SNAPSHOT, Java 17. API baseline 7faaf4f0516c.

Prerequisites and routing

Start a server with an address space and a client event subscription. Events have typed field values rather than a Variable Value notification. The client's event item monitors the EventNotifier attribute and provides an EventFilter with select clauses and an optional where clause; see Client subscriptions.

SourceNode identifies the source of an occurrence. HasEventSource and HasNotifier form a separate routing hierarchy. Setting SourceNode alone does not build that hierarchy. Set the SubscribeToEvents bit on Objects that clients will monitor, then wire paired forward and inverse references. ManagedNamespace.registerEventNotifier(object) marks and connects a namespace notifier to the Server Object; add the source relationships appropriate to your own hierarchy.

For a monitored Object M, an event reaches the item when its source is M or reachable through forward HasNotifier/HasEventSource references, including subtypes. Routing walks inverse references from the source at fire time, so both directions matter. An item on the standard Server Object receives all fired events before its filter applies. Events without a usable source hierarchy reach only that root item's scope. Non-MonitoredItem application listeners registered directly with the event notifier receive events regardless of scope.

Instantiate, populate, and fire

server.getEventInstantiator() creates an event instance and its fields from its event type. It sets EventType to the requested type automatically. The standard fields include EventId, EventType, SourceNode/Name, Time, ReceiveTime, Message, and Severity. Use a unique EventId for each occurrence. Time is the occurrence time; ReceiveTime is when this server received it. Keep severity within the application's OPC UA event policy.

Here eventId is a fresh NodeId in the application's registered namespace, and sourceId is a real source node. The example targets root Server monitoring, so it needs no additional notifier subtree. Import BaseEventTypeNode from org.eclipse.milo.opcua.sdk.server.model.objects, NodeIds from org.eclipse.milo.opcua.stack.core, ByteString, DateTime, and LocalizedText from org.eclipse.milo.opcua.stack.core.types.builtin, java.util.UUID, java.nio.charset.StandardCharsets, and static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ushort.

BaseEventTypeNode event =
    server.getEventInstantiator().createEvent(eventId, NodeIds.BaseEventType);
try {
  event.setEventId(
      ByteString.of(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)));
  event.setSourceNode(sourceId);
  event.setSourceName("Temperature");
  event.setTime(DateTime.now());
  event.setReceiveTime(DateTime.now());
  event.setMessage(LocalizedText.english("Temperature changed"));
  event.setSeverity(ushort(321));
  server.getEventNotifier().fire(event);
} finally {
  event.delete();
}

A root event item selecting Message and SourceNode receives Temperature changed and the selected source NodeId. The temporary event nodes are deleted after synchronous firing has let listeners extract fields. Application listeners retaining information must copy the values they need rather than rely on live nodes surviving. Use try/finally so population or firing failures do not leak nodes.

For custom event types, instantiate the actual subtype and preserve the EventType set by the instantiator. Use createEvent(Class<T>, NodeId, NodeId) when you need the generated Java subtype. Publish its type hierarchy and field declarations so clients can form correct select clauses. A declaration without a populated value can yield a null selected field. A type that cannot be instantiated, an unknown type, or a collision is a construction error; it is not a delivered event.

Filters and application responsibilities

Notifier routing limits candidate recipients; the client's filter then chooses and projects fields. Verify monitored-item creation results and filter diagnostics before debugging event generation. An Object without SubscribeToEvents yields Bad_AttributeIdInvalid. A missing or undecodable event filter yields Bad_MonitoredItemFilterInvalid. Access denial fails event-item creation with the controller's status; unlike a data item, it cannot carry the denial in a later DataValue. A where clause can validly exclude an event even though routing and fire succeeded. Queue limits and publish timing still apply.

Do not treat client where clauses as authorization. If an event contains data that some Sessions must not see, design the event access policy and source/field exposure explicitly. The data-value UserAccessLevel sampling cache is not a per-event permission system.

Use Alarms and Conditions for retained state, acknowledgement, shelving, and refresh. Repeatedly firing BaseEventType nodes does not implement those semantics. Event history and durable persistence also remain separate application work.

Cleanup and migration

Delete temporary ordinary event instances after firing. Unregister application event listeners when their owner stops, and retire notifier/source nodes after their producers stop. Condition behavior owns longer-lived state and must be unregistered through its manager before node retirement.

EventFactory is deprecated in favor of EventInstantiator. The instantiation package is experimental for one minor release. When migrating, compare optional fields and persisted derived IDs, and keep event-node lifetime separate from persistent source identity. The linked GenerateEventMethod is an older source example: it repeats the fixed EventId {0,1,2,3}, overwrites EventType with BaseEventType even when another type was requested, and deletes nodes without finally. Do not copy those choices. The fragment above preserves the instantiator's type, generates unique occurrence IDs, and guarantees cleanup.

Examples and reference

Related pages

Server SDK · Alarms and Conditions · Client subscriptions

Clone this wiki locally