public void uncaughtException(Thread t, Throwable e) {
   if (e instanceof Error) {
     // Speicherreserve freigeben, damit die Ausgaben nach einem OutOfMemoryError funktionieren
     _reserve = null;
     try {
       System.err.println(
           "Schwerwiegender Laufzeitfehler: Ein Thread hat sich wegen eines Errors beendet, Prozess wird terminiert");
       System.err.println(t);
       e.printStackTrace(System.err);
       _debug.error(
           "Schwerwiegender Laufzeitfehler: "
               + t
               + " hat sich wegen eines Errors beendet, Prozess wird terminiert",
           e);
     } catch (Throwable ignored) {
       // Weitere Fehler während der Ausgaben werden ignoriert, damit folgendes exit() auf jeden
       // Fall ausgeführt wird.
     }
     System.exit(1);
   } else {
     System.err.println("Laufzeitfehler: Ein Thread hat sich wegen einer Exception beendet:");
     System.err.println(t);
     e.printStackTrace(System.err);
     _debug.error("Laufzeitfehler: " + t + " hat sich wegen einer Exception beendet", e);
   }
 }
  /**
   * Diese Methode startet einen Login-Dialog und meldet sich anhand der eingetragenen IP-Adresse,
   * Portnummer, Benutzername und Passwort beim Datenverteiler an.
   *
   * @param application Applikation, die eine Verbindung zum Datenverteiler benötigt.
   * @param applicationTypePid Pid des Applikationstyps. Der Datenverteiler erzeugt für die
   *     Appliaktion ein Objekt dieses Typs. Der Applikationstyp sollte "typ.applikation" sein oder
   *     davon abgeleitet sein.
   * @param args Aufrufargumente der Applikation
   */
  public static void run(GUIApplication application, String applicationTypePid, String[] args) {
    createApplicationLabel(args);
    final ArgumentList argumentList = new ArgumentList(args);
    initializeDebug(application, argumentList);
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler());
    try {
      // soll der Login-Dialog überhaupt angezeigt werden?
      boolean autoLogin = argumentList.fetchArgument("-autologin=false").booleanValue();
      if (autoLogin) {
        if (!(argumentList.hasArgument("-benutzer")
            && argumentList.hasArgument("-authentifizierung"))) {
          if (argumentList.hasArgument("-benutzer")) argumentList.fetchArgument("-benutzer");
          if (argumentList.hasArgument("-authentifizierung")) {
            argumentList.fetchArgument("-authentifizierung");
          }
          _debug.warning(
              "Der Login-Dialog wird trotz des Aufrufparameters '-autologin' aufgerufen, da die Parameter '-benutzer' und '-authentifizierung' "
                  + "unvollständig oder nicht korrekt angegeben wurden.");
          autoLogin = false;
        }
      }

      // ArgumentListe wird in ClientDavParameters konvertiert
      final ClientDavParameters parameters = new ClientDavParameters(argumentList);
      // zuerst darf die Applikation die ArgumentListe durcharbeiten
      parameters.setApplicationTypePid(applicationTypePid);
      parameters.setApplicationName(_applicationName);
      application.parseArguments(argumentList);
      argumentList.ensureAllArgumentsUsed();

      //			System.out.println("IP: " + parameters.getDavCommunicationAddress() + " Port: " +
      // parameters.getDavCommunicationSubAddress());
      ClientDavInterface connection = null;
      if (autoLogin) {
        connection = new ClientDavConnection(parameters);
        // Verbindung aufbauen (inkl. Anmelden zur Fertigmeldung für Start/Stop)
        establishConnection(connection);
      } else {
        // Login-Dialog aufrufen, der eine Verbindung zum Datenverteiler aufbaut und zurückgibt.
        connection = application.connect(parameters);
      }
      if (connection != null) {
        _applicationLabel.append(
            connection.getLocalConfigurationAuthority().getPid()); // ApplikationsKennung
        MessageSender.getInstance()
            .init(connection, _applicationName, _applicationLabel.toString());
        application.initialize(connection);
        // Fertigmeldung senden
        connection.sendApplicationReadyMessage();
      } else {
        throw new RuntimeException(
            "Die Verbindung zum Datenverteiler konnte nicht hergestellt werden.");
      }
    } catch (Exception ex) {
      _debug.error("Fehler in der Applikation", ex);
      System.exit(1);
    }
  }
 /**
  * Diese Methode erstellt eine Verbindung zum Datenverteiler anhand der Standard-Parameter her.
  *
  * @param application Applikation, die eine Verbindung zum Datenverteiler benötigt.
  * @param applicationTypePid Pid des Applikationstyps. Der Datenverteiler erzeugt für die
  *     Appliaktion ein Objekt dieses Typs. Der Applikationstyp sollte "typ.applikation" sein oder
  *     davon abgeleitet sein.
  * @param args Aufrufargumente der Applikation
  */
 public static void run(
     StandardApplication application, String applicationTypePid, String[] args) {
   createApplicationLabel(args);
   final ArgumentList argumentList = new ArgumentList(args);
   initializeDebug(application, argumentList);
   Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler());
   try {
     // ArgumentListe wird in ClientDavParameters konvertiert
     final ClientDavParameters parameters = new ClientDavParameters(argumentList);
     parameters.setApplicationTypePid(applicationTypePid);
     parameters.setApplicationName(_applicationName);
     // zuerst darf die Applikation die ArgumentListe durcharbeiten
     application.parseArguments(argumentList);
     argumentList.ensureAllArgumentsUsed();
     final ClientDavInterface connection = new ClientDavConnection(parameters);
     // Fertigmeldung für Start/Stop wird eplizit selbst übernommen
     establishConnection(connection);
     _applicationLabel.append(
         connection.getLocalConfigurationAuthority().getPid()); // ApplikationsKennung
     MessageSender.getInstance().init(connection, _applicationName, _applicationLabel.toString());
     application.initialize(connection);
     // Fertigmeldung wird gesendet
     connection.sendApplicationReadyMessage();
   } catch (Exception ex) {
     _debug.error("Fehler", ex);
     System.exit(1);
   }
 }
 /**
  * Diese Methode initialisiert den Debug-Logger.
  *
  * @param application Applikations-Objekt
  * @param argumentList Aufrufargumente
  */
 private static void initializeDebug(Object application, ArgumentList argumentList) {
   // Der Klassenname wird für die Initialisierung des Debug benötigt.
   //		System.out.println("application.getClass().getName() = " +
   // application.getClass().getName());
   final String[] classNameParts = application.getClass().getName().split("[.]");
   //		System.out.println("classNameParts.length = " + classNameParts.length);
   final int lastPartIndex = classNameParts.length - 1;
   final String name;
   if (lastPartIndex < 0) {
     name = "StandardApplication";
   } else {
     name = classNameParts[lastPartIndex];
   }
   _applicationName = name;
   _applicationLabel.append(name);
   Debug.init(name, argumentList);
   _debug = Debug.getLogger();
 }
  /**
   * Liefert das System-Objekt mit der angegebenen PID zurück.
   *
   * @param pid Die permanente ID des System-Objekts
   * @return Das gewünschte System-Objekt oder <code>null</code>, wenn es kein Objekt mit der
   *     angegebenen PID gibt.
   * @see de.bsvrz.dav.daf.main.config.DataModel
   */
  public SystemObject getObject(String pid) {
    if (pid == null || pid.equals("") || pid.equals("null")) return null;
    SystemObject object = _dataModel.getObject(pid);
    if (isValid(object)) return object;
    synchronized (this) {
      // Sans, STS, KonfigAss: Korrektur _newlyActiveObjects
      if (_newlyActiveObjects == null) {
        _newlyActiveObjects = new HashMap<String, SystemObject>();

        long startTime = System.currentTimeMillis();
        final Map<String, ConfigurationArea> areas =
            ((ConfigDataModel) _dataModel).getAllConfigurationAreas();
        for (ConfigurationArea configurationArea : areas.values()) {
          final Collection<SystemObject> newObjects = configurationArea.getNewObjects();
          for (SystemObject newObject : newObjects) {
            final String newObjectPid = newObject.getPid();
            if (newObjectPid != null && newObjectPid.length() > 0 && isValid(newObject)) {
              _newlyActiveObjects.put(newObjectPid, newObject);
            }
          }

          _debug.fine(
              "Zwischenspeicherung von neuerdings aktiven Objekten dauerte in Millisekunden",
              System.currentTimeMillis() - startTime);
        }
      }
      return _newlyActiveObjects.get(pid);
    }

    //    final Set<ConfigurationArea> configurationAreas = _configurationAreaVersions.keySet();
    //    for(ConfigurationArea configurationArea : configurationAreas) {
    //      final Collection<SystemObject> newObjects = configurationArea.getNewObjects();
    //      for(SystemObject systemObject : newObjects) {
    //        if(systemObject.getPid().equals(pid) && isValid(systemObject)) return systemObject;
    //      }
    //    }
    //    return null;
  }
/**
 * @author Kappich Systemberatung
 * @version $Revision: 6339 $
 */
public class ReceiveSubscriptionInfo {

  private static final Debug _debug = Debug.getLogger();

  /** Die Basisanmeldeinformationen */
  private BaseSubscriptionInfo _baseSubscriptionInfo;

  /** Anmeldeoptionen der Empfangsanmeldungen */
  private ReceiveOptions _receiveOptions;

  /** Die Applikationsrolle */
  private ReceiverRole _receiverRole;

  /** Der Index der letzten Datensatz der vom Datenverteiler zur Applikation geschickt wurde. */
  private long _lastDataIndex = 0;

  /** Der letzte Zustand des Fehlerstatus */
  private byte _lastErrorState;

  /** Creates new ReceiveSubscriptionInfo */
  public ReceiveSubscriptionInfo() {}

  /**
   * Erzeugt ein neues Objekt mit den gegebenen Parametern.
   *
   * @param baseSubscriptionInfo Basisanmeldeinformationen
   * @param receiveOptions Anmeldeoptionen der Empfangsanmeldungen
   * @param receiverRole ApplikationsRole
   */
  public ReceiveSubscriptionInfo(
      BaseSubscriptionInfo baseSubscriptionInfo,
      ReceiveOptions receiveOptions,
      ReceiverRole receiverRole) {
    _baseSubscriptionInfo = baseSubscriptionInfo;
    _receiveOptions = receiveOptions;
    _receiverRole = receiverRole;
  }

  /**
   * Gibt die Basisanmeldeinformationen zurück.
   *
   * @return Basisanmeldeinformationen
   */
  public final BaseSubscriptionInfo getBaseSubscriptionInfo() {
    return _baseSubscriptionInfo;
  }

  /**
   * Gibt an, ob Interesse an nachgelieferten oder an aktuellen Datensätzen besteht.
   *
   * @return <code>true:</code> nachgelieferte Datensätze erwünscht, <code>false:</code>
   *     nachgelieferte Datensätze nicht erwünscht
   */
  public final boolean getDelayedDataFlag() {
    return _receiveOptions.withDelayed();
  }

  /**
   * Gibt an, ob Interesse an nur den geänderten Datensätzen oder an allen Datensätzen besteht.
   *
   * @return <code>true:</code> nur geänderte Datensätze erwünscht, <code>false:</code> alle
   *     Datensätze erwünscht
   */
  public final boolean getDeltaDataFlag() {
    return _receiveOptions.withDelta();
  }

  /**
   * Gibt an, ob die Applikation als ein normaler Empfänger für diese Datums angemeldet ist oder
   * nicht.
   *
   * @return <code>true:</code> Applikation ist normaler Emfänger, <code>false:</code> Applikation
   *     ist kein normaler Empfänger
   */
  public final boolean isReceiver() {
    return _receiverRole.isReceiver();
  }

  /**
   * Gibt an, ob die Applikation als Senke für dieses Datum angemeldet ist oder nicht.
   *
   * @return <code>true:</code>Applikation ist als Senke angemeldet, <code>false:</code>Applikation
   *     ist nicht als Senke angemeldet.
   */
  public final boolean isDrain() {
    return _receiverRole.isDrain();
  }

  /**
   * Gibt die Informationen über die Empfangsoptionen zurück.
   *
   * @return Informationen über die Empfangsoptionen
   */
  public final ReceiveOptions getReceiveOptions() {
    return _receiveOptions;
  }

  /**
   * Gibt die Informationen über die Empfangsapplikationsrole zurück.
   *
   * @return Informationen über die Empfangsapplikationsrole
   */
  public final ReceiverRole getReceiverRole() {
    return _receiverRole;
  }

  /**
   * Gibt den letzten Index des Datensatzes, den die Applikation empfangen hat, zurück.
   *
   * @return Index des Datensatzes
   */
  public final long getLastDataIndex() {
    return _lastDataIndex;
  }

  /**
   * Setzt den letzten Index des Datensatzes, den die Applikation empfangen hat.
   *
   * @param newDataIndex Datenindex
   */
  public final void setLastDataIndex(long newDataIndex) {
    //		final short attributeGroupCode = baseSubscriptionInfo.getAttributeGroupCode();
    //		final boolean normalIndex = (lastDataIndex != 0) && ((lastDataIndex & 0x0000000000000003L)
    // == 0) && ((newDataIndex & 0x0000000000000003L) == 0);
    //		if((lastDataIndex != newDataIndex) && normalIndex) {
    //			long oldSequence = (lastDataIndex >>> 2) & 0x3fffffff;
    //			long newSequence = (newDataIndex >>> 2) & 0x3fffffff;
    //			if((oldSequence + 1 != newSequence)) {
    //				_debug.warning("Datensatzindex nicht fortlaufend" +
    //				               ", Objekt: " + baseSubscriptionInfo.getObjectID() +
    //				               ", Attributgruppe: " + attributeGroupCode +
    //				               ", Aspekt: " + baseSubscriptionInfo.getAspectCode() +
    //				               ", letzter Index: " + (lastDataIndex>>> 32) + "#" + ((lastDataIndex &
    // 0xffffffffL) >> 2) + "#" + (lastDataIndex & 3) +
    //				               ", aktueller Index: " + (newDataIndex >>> 32) + "#" + ((newDataIndex &
    // 0xffffffffL) >> 2) + "#" + (newDataIndex & 3)
    //				);
    //			}
    //		}
    _lastDataIndex = newDataIndex;
  }

  /**
   * Gibt den letzten Fehlerstatus zurück.
   *
   * @return letzter Fehlerstatus
   */
  public final byte getLastErrorState() {
    return _lastErrorState;
  }

  /**
   * Setzt den letzten Fehlerstatus.
   *
   * @param error Fehlerstatus
   */
  public final void setLastErrorState(byte error) {
    _lastErrorState = error;
  }

  /**
   * Gibt eine Kopie des Objektes zurück.
   *
   * @return Kopie des Objektes
   */
  public final ReceiveSubscriptionInfo cloneObject() {
    return new ReceiveSubscriptionInfo(_baseSubscriptionInfo, _receiveOptions, _receiverRole);
  }

  /**
   * Aktualisiert diese Empfangsanmeldeinformationen durch Vereinigung mit einer weiteren
   * Empfangsanmeldeinformation
   *
   * @param receiveSubscriptionInfo Weitere Empfangsanmeldeinformation
   * @return <code>true<code> bei Änderung dieser Empfangsanmeldeinformation, </code>false</code>
   *     sonst
   */
  public final boolean updateSubscriptionInfo(ReceiveSubscriptionInfo receiveSubscriptionInfo) {
    BaseSubscriptionInfo _baseSubscriptionInfo = receiveSubscriptionInfo.getBaseSubscriptionInfo();
    ReceiveOptions options = receiveSubscriptionInfo.getReceiveOptions();
    ReceiverRole role = receiveSubscriptionInfo.getReceiverRole();

    boolean changed = false;
    if ((_baseSubscriptionInfo == null) || (options == null) || (role == null)) {
      return false;
    }
    if (_baseSubscriptionInfo.getObjectID() != this._baseSubscriptionInfo.getObjectID()) {
      return false;
    }
    boolean delayed = getDelayedDataFlag();
    boolean delta = getDeltaDataFlag();
    if (!delayed) {
      if (options.withDelayed()) {
        delayed = true;
        changed = true;
      }
    }
    if (delta) {
      if (!options.withDelta()) {
        delta = false;
        changed = true;
      }
    }
    if (changed) {
      _receiveOptions = new ReceiveOptions(delta, delayed);
    }
    // wenn receiverRole Empfänger ist, dann darf keine Senke angemeldet werden
    // wenn receiverRole Senke ist, dann darf keine weitere Senke angemeldet werden
    if (_receiverRole.isReceiver() || _receiverRole.isDrain()) {
      if (role.isDrain()) {
        // zu einem Empfänger oder einer Senke soll noch eine Senke angemeldet werden
        throw new IllegalStateException(
            "Ungültige Anmeldung. Zu einem Empfänger oder einer Senke darf keine weitere Senke angemeldet werden.");
      }
    }
    return changed;
  }

  /**
   * Gibt einen String zurrück, der diesen Datensatz beschreibt.
   *
   * @return String, der diesen Datensatz beschreibt
   */
  public final String parseToString() {
    String str = "Empfangsanmeldeinformationen:\n";
    str += _baseSubscriptionInfo.toString() + "\n";
    str += "Nachgeliefert Flag   : " + getDelayedDataFlag() + "\n";
    str += "Delta Daten Flag     : " + getDeltaDataFlag() + "\n";
    str += "Empfangsapplikation  : " + isReceiver() + "\n";
    str += "Senkeapplikation     : " + isDrain() + "\n";
    return str;
  }

  /**
   * Schreiben eines Datensatzes in den übergegebenen DataOutputStream
   *
   * @param out DataOutputStream
   * @throws IOException, wenn ein Fehler beim Schreiben in den Ausgabestream auftritt.
   */
  public final void write(DataOutputStream out) throws IOException {
    _baseSubscriptionInfo.write(out);
    out.writeBoolean(_receiveOptions.withDelayed());
    out.writeBoolean(_receiveOptions.withDelta());
    out.writeBoolean(_receiverRole.isDrain());
    // Ein Byte Länge des nicht mehr benötigten Indikatorbitfelds
    out.writeByte(0);
  }

  /**
   * Lesen eines Datensatzes vom übergegebenen DataInputStream
   *
   * @param in DataInputStream
   * @throws IOException, wenn ein Fehler beim Lesen des Streams auftritt.
   */
  public final void read(DataInputStream in) throws IOException {
    _baseSubscriptionInfo = new BaseSubscriptionInfo();
    _baseSubscriptionInfo.read(in);
    boolean delayedDataFlag = in.readBoolean();
    boolean deltaDataFlag = in.readBoolean();
    _receiveOptions = new ReceiveOptions(deltaDataFlag, delayedDataFlag);
    boolean applikationStatus = in.readBoolean();
    _receiverRole = new ReceiverRole(applikationStatus);
    int size = (int) in.readByte();
    if (size > 0) {
      byte[] ignoredAttributesIndicator = new byte[size];
      for (int i = 0; i < size; ++i) {
        ignoredAttributesIndicator[i] = in.readByte();
      }
    }
  }

  /**
   * Gibt die Länge dieses Telegrams zurück
   *
   * @return die Länge dieses Telegrams
   */
  public int getLength() {
    return 18;
  }
}
/**
 * Klasse zum Zugriff auf Konfigurationdaten, bei der für jeden Konfigurationsbereich eine bestimmte
 * vorgegebene Version berücksichtigt wird. Beim Erzeugen des Objekts wird dem Konstruktor
 * mitgeteilt, welcher Konfigurationsbereich in welcher Version zu betrachten ist. Alle
 * Abfragemethoden berücksichtigen dann die angegebenen Versionen.
 *
 * @author Kappich Systemberatung
 * @version $Revision: 0 $
 */
public class VersionedView implements ObjectLookup {

  /** DebugLogger für Debug-Ausgaben */
  private static final Debug _debug = Debug.getLogger();

  private DataModel _dataModel;

  private Map<ConfigurationArea, Short> _configurationAreaVersions;

  /**
   * Map der aktuell noch nicht gültigen Objekte, die aber in der durch den View zu betrachtenden
   * Version gültig werden. Schlüssel ist die Pid des Objekts.
   */
  private Map<String, SystemObject> _newlyActiveObjects = null;

  public VersionedView(
      final DataModel dataModel, final Map<ConfigurationArea, Short> configurationAreaVersions) {
    _dataModel = dataModel;
    _configurationAreaVersions = configurationAreaVersions;
  }

  /**
   * Bestimmt, ob das angegebene System-Objekt ein Element des angegebenen Typs ist. Ein
   * System-Objekt ist Element des Typs, wenn der Typ des Objekts mit dem angegebenen Typ
   * übereinstimmt oder diesen erweitert.
   *
   * @param object Zu prüfendes Objekt.
   * @param ancestorType Zu prüfender Typ.
   * @return <code>true</code>, wenn der übergebene Typ mit dem Typ des Objekts oder mit einem der
   *     direkten oder indirekten Vorgänger in der Vererbungshierarchie übereinstimmt; sonst <code>
   *     false</code>.
   */
  public boolean isOfType(SystemObject object, SystemObjectType ancestorType) {
    final SystemObjectType objectType = object.getType();
    if (ancestorType == objectType) return true;
    return inheritsFrom(objectType, ancestorType);
  }

  /**
   * Prüft, ob der angegebene Typ <code>ancestorType</code> in der Typhierarchie oberhalb
   * angegebenen Typs <code>derivedType</code> vorkommt. Dies ist dann der Fall, wenn <code>
   * derivedType</code> direkt oder indirekt <code>ancestorType</code> erweitert und damit dessen
   * Eigenschaften erbt.
   *
   * @param derivedType Zu prüfender abgeleiteter Typ
   * @param ancestorType Zu prüfender übergeordneter Typ
   * @return <code>true</code> wenn <code>derivedType</code> direkt oder indirekt <code>ancestorType
   *     </code> erweitert, sonst <code>false</code>.
   */
  public boolean inheritsFrom(
      final SystemObjectType derivedType, final SystemObjectType ancestorType) {
    final Collection<SystemObjectType> superTypes = getSuperTypes(derivedType);
    // direkte Vererbung
    if (superTypes.contains(ancestorType)) return true;
    // indirekte Vererbung
    for (SystemObjectType superType : superTypes) {
      if (inheritsFrom(superType, ancestorType)) return true;
    }
    return false;
  }

  /**
   * Liefert eine Liste der Typ-Objekte die von dem angegebenen Typ-Objekt erweitert werden.
   *
   * @return Liste von {@link SystemObjectType Typ-Objekten}
   */
  public Collection<SystemObjectType> getSuperTypes(final SystemObjectType type) {
    Collection<SystemObjectType> superTypes = new ArrayList<SystemObjectType>();
    NonMutableSet set = (NonMutableSet) type.getObjectSet("SuperTypen");
    if (set != null) {
      final Collection<SystemObject> elements = getElements(set);
      for (SystemObject systemObject : elements) {
        superTypes.add((SystemObjectType) systemObject);
      }
    }
    return superTypes;
  }

  public List<ObjectSetUse> getDirectObjectSetUses(SystemObjectType type) {
    List<ObjectSetUse> directObjectSetUses = new ArrayList<ObjectSetUse>();
    ObjectSet set = type.getObjectSet("Mengen");
    if (set != null) {
      for (SystemObject systemObject : getElements(set)) {
        directObjectSetUses.add((ObjectSetUse) systemObject);
      }
    }
    return directObjectSetUses;
  }

  public List<ObjectSetUse> getObjectSetUses(SystemObjectType type) {
    Set<ObjectSetUse> objectSetUses = new HashSet<ObjectSetUse>();
    objectSetUses.addAll(getDirectObjectSetUses(type));
    for (SystemObjectType superType : getSuperTypes(type)) {
      objectSetUses.addAll(getObjectSetUses(superType));
    }
    return new ArrayList(objectSetUses);
  }

  /**
   * Bestimmt die Elemente der angegebenen Menge
   *
   * @param set Zu betrachtende Menge.
   * @return Elemente der Menge.
   */
  public Collection<SystemObject> getElements(final ObjectSet set) {
    if (set instanceof NonMutableSet) {
      NonMutableSet nonMutableSet = (NonMutableSet) set;
      short version = getVersion(nonMutableSet);
      return nonMutableSet.getElementsInVersion(version);
    }
    if (set instanceof MutableSet) {
      MutableSet mutableSet = (MutableSet) set;
      return mutableSet.getElements();
    }
    throw new IllegalStateException("ObjektMenge hat einen unbekannten Typ");
  }

  /**
   * Bestimmt die betrachtete Version des Konfigurationsbereichs in dem das angegebene Objekt
   * enthalten ist.
   *
   * @param object Systemobjekt zu dem die Version ermittelt werden soll.
   * @return Version des Konfigurationsbereichs des angegebenen Systemobjekts
   */
  public short getVersion(final SystemObject object) {
    final ConfigurationArea configurationArea = object.getConfigurationArea();
    Short version = _configurationAreaVersions.get(configurationArea);
    if (version != null) return version.shortValue();
    // throw new IllegalStateException("Version des Konfigurationsbereichs " +
    // object.getConfigurationArea().getPidOrNameOrId() + " nicht definiert");
    // Falls in der Map ein Konfigurationsbereich nicht enthalten ist, dann wird die aktive Version
    // des Bereichs zurückgegeben.
    return configurationArea.getActiveVersion();
  }

  /**
   * Liefert das System-Objekt mit der angegebenen PID zurück.
   *
   * @param pid Die permanente ID des System-Objekts
   * @return Das gewünschte System-Objekt oder <code>null</code>, wenn es kein Objekt mit der
   *     angegebenen PID gibt.
   * @see de.bsvrz.dav.daf.main.config.DataModel
   */
  public SystemObject getObject(String pid) {
    if (pid == null || pid.equals("") || pid.equals("null")) return null;
    SystemObject object = _dataModel.getObject(pid);
    if (isValid(object)) return object;
    synchronized (this) {
      // Sans, STS, KonfigAss: Korrektur _newlyActiveObjects
      if (_newlyActiveObjects == null) {
        _newlyActiveObjects = new HashMap<String, SystemObject>();

        long startTime = System.currentTimeMillis();
        final Map<String, ConfigurationArea> areas =
            ((ConfigDataModel) _dataModel).getAllConfigurationAreas();
        for (ConfigurationArea configurationArea : areas.values()) {
          final Collection<SystemObject> newObjects = configurationArea.getNewObjects();
          for (SystemObject newObject : newObjects) {
            final String newObjectPid = newObject.getPid();
            if (newObjectPid != null && newObjectPid.length() > 0 && isValid(newObject)) {
              _newlyActiveObjects.put(newObjectPid, newObject);
            }
          }

          _debug.fine(
              "Zwischenspeicherung von neuerdings aktiven Objekten dauerte in Millisekunden",
              System.currentTimeMillis() - startTime);
        }
      }
      return _newlyActiveObjects.get(pid);
    }

    //    final Set<ConfigurationArea> configurationAreas = _configurationAreaVersions.keySet();
    //    for(ConfigurationArea configurationArea : configurationAreas) {
    //      final Collection<SystemObject> newObjects = configurationArea.getNewObjects();
    //      for(SystemObject systemObject : newObjects) {
    //        if(systemObject.getPid().equals(pid) && isValid(systemObject)) return systemObject;
    //      }
    //    }
    //    return null;
  }

  public boolean isValid(final SystemObject object) {
    if (object == null) return false;
    if (object instanceof ConfigurationObject) {
      ConfigurationObject configurationObject = (ConfigurationObject) object;
      short viewingVersion = getVersion(configurationObject);
      final short validSince = configurationObject.getValidSince();
      final short notValidSince = configurationObject.getNotValidSince();
      return validSince <= viewingVersion && (notValidSince == 0 || viewingVersion < notValidSince);
    } else return object.isValid();
  }

  /**
   * Liefert das System-Objekt mit der angegebenen Objekt-ID zurück.
   *
   * @param id Die Objekt-ID des System-Objekts
   * @return Das gewünschte System-Objekt oder <code>null</code>, wenn es kein Objekt mit der
   *     angegebenen ID gibt.
   * @see de.bsvrz.dav.daf.main.config.DataModel
   */
  public SystemObject getObject(long id) {
    return _dataModel.getObject(id);
  }
}