code: /*
   * Copyright (c) 2019 the Eclipse Milo Authors
   *
   * This program and the accompanying materials are made
   * available under the terms of the Eclipse Public License 2.0
   * which is available at https://www.eclipse.org/legal/epl-2.0/
   *
   * SPDX-License-Identifier: EPL-2.0
   */
  
  package org.eclipse.milo.opcua.sdk.server.namespaces;
  
  import java.util.List;
  import java.util.NoSuchElementException;
  
  import org.eclipse.milo.opcua.sdk.core.AccessLevel;
  import org.eclipse.milo.opcua.sdk.server.Lifecycle;
  import org.eclipse.milo.opcua.sdk.server.LifecycleManager;
  import org.eclipse.milo.opcua.sdk.server.OpcUaServer;
  import org.eclipse.milo.opcua.sdk.server.api.AddressSpaceComposite;
  import org.eclipse.milo.opcua.sdk.server.api.AddressSpaceFilter;
  import org.eclipse.milo.opcua.sdk.server.api.DataItem;
  import org.eclipse.milo.opcua.sdk.server.api.ManagedAddressSpaceFragmentWithLifecycle;
  import org.eclipse.milo.opcua.sdk.server.api.MonitoredItem;
  import org.eclipse.milo.opcua.sdk.server.api.Namespace;
  import org.eclipse.milo.opcua.sdk.server.api.SimpleAddressSpaceFilter;
  import org.eclipse.milo.opcua.sdk.server.diagnostics.objects.ServerDiagnosticsObject;
  import org.eclipse.milo.opcua.sdk.server.model.nodes.objects.ServerDiagnosticsTypeNode;
  import org.eclipse.milo.opcua.sdk.server.util.SubscriptionModel;
  import org.eclipse.milo.opcua.stack.core.Identifiers;
  import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort;
  
  public class ServerNamespace extends AddressSpaceComposite implements Lifecycle, Namespace {
  
      private final LifecycleManager lifecycleManager = new LifecycleManager();
  
      private final String namespaceUri;
      private final UShort namespaceIndex;
  
      public ServerNamespace(OpcUaServer server) {
          super(server);
  
          this.namespaceUri = server.getConfig().getApplicationUri();
          this.namespaceIndex = server.getNamespaceTable().addUri(namespaceUri);
  
          lifecycleManager.addLifecycle(new Lifecycle() {
              @Override
              public void startup() {
                  server.getAddressSpaceManager().register(ServerNamespace.this);
              }
  
              @Override
              public void shutdown() {
                  server.getAddressSpaceManager().unregister(ServerNamespace.this);
              }
          });
  
          DiagnosticsFragment diagnosticsFragment = new DiagnosticsFragment(server);
          lifecycleManager.addLifecycle(diagnosticsFragment);
  
          VendorServerInfoFragment vendorServerInfoFragment = new VendorServerInfoFragment(server);
          lifecycleManager.addLifecycle(vendorServerInfoFragment);
      }
  
      @Override
      public final void startup() {
          lifecycleManager.startup();
      }
  
      @Override
      public final void shutdown() {
          lifecycleManager.shutdown();
      }
  
      @Override
      public String getNamespaceUri() {
          return namespaceUri;
      }
  
      @Override
      public UShort getNamespaceIndex() {
          return namespaceIndex;
      }
  
      private class DiagnosticsFragment extends ManagedAddressSpaceFragmentWithLifecycle {
  
          private final AddressSpaceFilter filter =
              SimpleAddressSpaceFilter.create(getNodeManager()::containsNode);
  
          private final SubscriptionModel subscriptionModel;
  
          public DiagnosticsFragment(OpcUaServer server) {
              super(server, ServerNamespace.this);
  
              subscriptionModel = new SubscriptionModel(server, this);
  
              ServerDiagnosticsTypeNode serverDiagnosticsNode = (ServerDiagnosticsTypeNode) getServer()
                  .getAddressSpaceManager()
                  .getManagedNode(Identifiers.Server_ServerDiagnostics)
                  .orElseThrow(() -> new NoSuchElementException("NodeId: " + Identifiers.Server_ServerDiagnostics));
  
              serverDiagnosticsNode.getEnabledFlagNode().setUserAccessLevel(
                  AccessLevel.toValue(AccessLevel.READ_WRITE)
              );
  
              ServerDiagnosticsObject serverDiagnosticsObject = new ServerDiagnosticsObject(
                  serverDiagnosticsNode,
                  getNodeManager()
              );
  
              getLifecycleManager().addLifecycle(subscriptionModel);
              getLifecycleManager().addLifecycle(serverDiagnosticsObject);
          }
  
          @Override
          public AddressSpaceFilter getFilter() {
              return filter;
          }
  
          @Override
          public void onDataItemsCreated(List<DataItem> dataItems) {
              subscriptionModel.onDataItemsCreated(dataItems);
          }
  
          @Override
          public void onDataItemsModified(List<DataItem> dataItems) {
              subscriptionModel.onDataItemsModified(dataItems);
          }
  
          @Override
          public void onDataItemsDeleted(List<DataItem> dataItems) {
              subscriptionModel.onDataItemsDeleted(dataItems);
          }
  
          @Override
          public void onMonitoringModeChanged(List<MonitoredItem> monitoredItems) {
              subscriptionModel.onMonitoringModeChanged(monitoredItems);
          }
  
      }
  
      private class VendorServerInfoFragment extends ManagedAddressSpaceFragmentWithLifecycle {
  
          private final AddressSpaceFilter filter =
              SimpleAddressSpaceFilter.create(getNodeManager()::containsNode);
  
          private final SubscriptionModel subscriptionModel;
  
          public VendorServerInfoFragment(OpcUaServer server) {
              super(server, ServerNamespace.this);
  
              subscriptionModel = new SubscriptionModel(server, this);
  
              getLifecycleManager().addLifecycle(subscriptionModel);
  
              getLifecycleManager().addStartupTask(() -> VendorServerInfoNodes.add(getNodeContext()));
          }
  
          @Override
          public AddressSpaceFilter getFilter() {
              return filter;
          }
  
          @Override
          public void onDataItemsCreated(List<DataItem> dataItems) {
              subscriptionModel.onDataItemsCreated(dataItems);
          }
  
          @Override
          public void onDataItemsModified(List<DataItem> dataItems) {
              subscriptionModel.onDataItemsModified(dataItems);
          }
  
          @Override
          public void onDataItemsDeleted(List<DataItem> dataItems) {
              subscriptionModel.onDataItemsDeleted(dataItems);
          }
  
          @Override
          public void onMonitoringModeChanged(List<MonitoredItem> monitoredItems) {
              subscriptionModel.onMonitoringModeChanged(monitoredItems);
          }
  
      }
  
  }
  