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); } }