/**
   * Anmeldung als Sender oder Quelle
   *
   * @param atg Attributgruppe
   * @param asp Aspekt
   * @param simulationVariant Simulationsvariante
   * @param senderRole Sender oder Quelle
   * @param senderObject Beliebiges Objekt das zu diesem Sender gespeichert wird. Jedes Objekt ist
   *     einer Datenidentifikation fest zugeordnet und kann nur einmal angemeldet werden.
   * @throws MissingObjectException Falls Attributgruppe oder Aspekt nicht vorhanden sind
   * @return true wenn das Objekt angemeldet wurde, sonst false.
   */
  public boolean registerSender(
      final String atg,
      final String asp,
      final short simulationVariant,
      final SenderRole senderRole,
      final KExDaVSender senderObject)
      throws MissingObjectException {
    if (atg == null) throw new IllegalArgumentException("atg ist null");
    if (asp == null) throw new IllegalArgumentException("asp ist null");
    if (senderRole == null) throw new IllegalArgumentException("senderRole ist null");
    if (senderObject == null) throw new IllegalArgumentException("senderObject ist null");

    if (_senders.containsKey(senderObject))
      throw new IllegalArgumentException("Der Sender " + senderObject + " ist bereits angemeldet.");

    final DataDescription dataDescription = makeDataDescription(atg, asp, simulationVariant);

    final InnerSender innerSender = new InnerSender(senderObject, dataDescription, senderRole);

    final SystemObject systemObject = getWrappedObject();
    if (systemObject == null) return true;

    if (!checkType(systemObject.getType(), dataDescription.getAttributeGroup())) return false;

    registerSender(innerSender, systemObject);
    return true;
  }
  /**
   * Erstellt ein neues KExDavObject
   *
   * @param objectSpecification Objekt-Spezifikation
   * @param connection Datenverteiler-Verbindung
   * @param manager KExDaV-Manager-Objekt, an das Benachrichtigungen gesendet werden können
   */
  public KExDaVObject(
      final ObjectSpecification objectSpecification,
      final ClientDavInterface connection,
      final ManagerInterface manager) {
    _manager = manager;
    if (objectSpecification == null)
      throw new IllegalArgumentException("objectSpecification ist null");
    if (connection == null) throw new IllegalArgumentException("connection ist null");

    _objectSpecification = objectSpecification;
    _connection = connection;

    final SystemObject object = objectSpecification.getObject(_connection.getDataModel());
    setWrappedObject(object);

    // Anmeldung auf Erstellung/Löschung des Objektes (nicht nötig bei schon vorhandenen
    // Konfigurationsobjekten)
    if (object == null || object.getType() instanceof DynamicObjectType) {
      /**
       * Direkt beim typ.dynamischesObject anmelden. Das Anmelden beim eigentlichen Typ dieses
       * Objektes funktioniert nicht immer zuverlässig, weil unter Umständen dieses Objekt noch gar
       * nicht vorhanden und deshalb kein Typ ermittelbar ist, oder weil evtl. jemand das Objekt mit
       * diesem Typ löschen könnte und ein anderes Objekt mit der gleichen Pid von einem anderen Typ
       * erstellen könnte
       */
      final DynamicObjectType dynamicObjectType =
          (DynamicObjectType) connection.getDataModel().getType(Constants.Pids.TypeDynamicObject);
      if (dynamicObjectType == null)
        throw new IllegalStateException(
            Constants.Pids.TypeDynamicObject + " konnte nicht gefunden werden");
      final Listener objectCreateDeleteListener = new Listener();
      dynamicObjectType.addInvalidationListener(objectCreateDeleteListener);
      dynamicObjectType.addObjectCreationListener(objectCreateDeleteListener);
    }
  }
  /**
   * Anmeldung als Empfänger/Senke
   *
   * @param atg Attributgruppe
   * @param asp Aspekt
   * @param simulationVariant Simulationsvariante
   * @param receiverRole (Empfänger oder Senke)
   * @param receiveOptions (Delta oder Nachgeliefert oder Normal)
   * @param receiver Objekt an das Empfangene Daten gesendet werden. Jedes Objekt ist einer
   *     Datenidentifikation fest zugeordnet und kann nur einmal angemeldet werden.
   * @throws MissingObjectException Falls Attributgruppe oder Aspekt nicht vorhanden sind
   */
  public boolean registerReceiver(
      final String atg,
      final String asp,
      final short simulationVariant,
      final ReceiverRole receiverRole,
      final ReceiveOptions receiveOptions,
      final KExDaVReceiver receiver)
      throws MissingObjectException {
    if (atg == null) throw new IllegalArgumentException("atg ist null");
    if (asp == null) throw new IllegalArgumentException("asp ist null");
    if (receiverRole == null) throw new IllegalArgumentException("receiverRole ist null");
    if (receiver == null) throw new IllegalArgumentException("receiver ist null");

    if (_receivers.containsKey(receiver))
      throw new IllegalArgumentException("Der Empfänger " + receiver + " ist bereits angemeldet.");

    final DataDescription dataDescription = makeDataDescription(atg, asp, simulationVariant);
    final InnerReceiver innerReceiver =
        new InnerReceiver(receiver, receiverRole, dataDescription, receiveOptions);

    final SystemObject systemObject = getWrappedObject();
    if (systemObject == null) return true;

    if (!checkType(systemObject.getType(), dataDescription.getAttributeGroup())) return false;

    registerReceiver(innerReceiver, systemObject);
    return true;
  }
 public static ExchangeProperties getExchangeProperties(final SystemObject wrappedObject)
     throws MissingKExDaVAttributeGroupException {
   final AttributeGroup attributeGroup =
       wrappedObject
           .getDataModel()
           .getAttributeGroup(Constants.Pids.AttributeGroupKExDaVConfigData);
   if (attributeGroup == null) throw new MissingKExDaVAttributeGroupException();
   Data data = wrappedObject.getConfigurationData(attributeGroup);
   if (data == null) return null;
   return new ExchangeProperties(data);
 }
 /**
  * Löscht dieses Objekt
  *
  * @param force Soll das Objekt auch gelöscht werden, wenn es nicht von KExDaV kopiert wurde?
  * @return true wenn das Objekt nicht mehr existiert, sonst false
  * @throws ConfigurationChangeException Falls das Ändern der Konfiguration fehlschlägt (z.B. keine
  *     Berechtigung)
  */
 public boolean invalidate(final boolean force)
     throws ConfigurationChangeException, MissingKExDaVAttributeGroupException {
   final SystemObject wrappedObject = getWrappedObject();
   if (wrappedObject == null || !wrappedObject.isValid()) {
     return true; // Objekt existiert nicht mehr, es braucht nicht nochmal gelöscht zu werden.
                  // Daher ist auch eine Warnung unnötig.
   }
   if (wrappedObject instanceof ConfigurationObject) {
     throw new IllegalArgumentException("Versuch, ein Konfigurationsobjekt zu löschen.");
   }
   if (!force && !isCopy()) return false;
   _manager.addMessage(Message.newInfo("Lösche Objekt: " + _objectSpecification));
   wrappedObject.invalidate();
   setWrappedObject(null);
   return true;
 }
 /**
  * Liest alle Konfigurationsdaten dieses Objekts
  *
  * @return Konfigurationsdaten
  * @throws MissingObjectException Falls ein Objekt fehlt (entweder das Systemobjekt, oder die
  *     Attributgruppe oder der Aspekt)
  */
 public Map<PidAttributeGroupUsage, KExDaVAttributeGroupData> getAllConfigurationData()
     throws MissingObjectException {
   final SystemObject wrappedObject = getWrappedObjectOrThrowException();
   final Map<PidAttributeGroupUsage, KExDaVAttributeGroupData> result =
       new HashMap<PidAttributeGroupUsage, KExDaVAttributeGroupData>();
   final List<AttributeGroup> attributeGroups = wrappedObject.getType().getAttributeGroups();
   for (final AttributeGroup attributeGroup : attributeGroups) {
     final Collection<Aspect> aspects = attributeGroup.getAspects();
     for (final Aspect aspect : aspects) {
       final Data data = wrappedObject.getConfigurationData(attributeGroup, aspect);
       if (data != null) {
         result.put(
             new PidAttributeGroupUsage(attributeGroup.getPid(), aspect.getPid()),
             new KExDaVAttributeGroupData(data, _manager));
       }
     }
   }
   return result;
 }
  private synchronized void setWrappedObject(final SystemObject wrappedObject) {
    if (_wrappedObject == wrappedObject) return;

    _wrappedObject = wrappedObject;
    if (wrappedObject != null) {
      for (final InnerReceiver receiver : _receivers.values()) {
        if (checkType(wrappedObject.getType(), receiver.getDataDescription().getAttributeGroup())) {
          registerReceiver(receiver, wrappedObject);
        }
      }
      for (final InnerSender sender : _senders.values()) {
        if (checkType(wrappedObject.getType(), sender.getDataDescription().getAttributeGroup())) {
          registerSender(sender, wrappedObject);
        }
      }
      for (final ExistenceListener listener : _existenceListeners) {
        listener.objectCreated(this);
      }
    } else {
      for (final ExistenceListener listener : _existenceListeners) {
        listener.objectInvalidated(this);
      }
    }
  }
 /**
  * Prüft ob das Objekt existiert
  *
  * @return True wenn es existiert
  */
 public boolean exists() {
   final SystemObject wrappedObject = getWrappedObject();
   return wrappedObject != null && wrappedObject.isValid();
 }
 @Override
 public String toString() {
   final SystemObject wrappedObject = getWrappedObject();
   if (wrappedObject != null) return wrappedObject.getPidOrNameOrId();
   return _objectSpecification.toString();
 }