Für einfache Business Entitys ist der Datenaustausch unter bestimmten Bedingungen ohne weiteren Entwicklungsaufwand möglich, da der Business Integration Service (BIS) einen generischen Import und Export unterstützt. Für komplexere Anwendungsfälle ist der klassische Datenaustausch zu verwenden. Dieser bietet größtmögliche Flexibilität.
Der vereinfachte Datenaustausch legt mehr Wert auf die Geschwindigkeit des Datenaustausches. Ein typischer Anwendungsfall des vereinfachten Datenaustausches wäre z. B. die periodische Übertragung immer derselben 10 Attribute des Business Objects „Partner“. Eine hohe Übertragungsgeschwindigkeit ergibt sich aufgrund immer derselben Struktur der Daten.
Dieses Dokument erläutert die grundlegenden Vorgehensweisen bei der Implementierung eines Controllers für den vereinfachten Datenaustausch und gibt Hinweise für die Verwendung der entsprechenden Programmierschnittstelle.
1 Zielgruppe
Anwendungsentwickler
2 Begriffsbestimmung
Controller
Der Controller ist eine Java-Klasse, die den Import bzw. Export eines Business Entitys realisiert. Für den vereinfachten Datenaustausch muss der konkrete Controller von der abstrakten Klasse „com.cisag.pgm.bi.lite.LiteController“ abgeleitet sein. Der Controller liefert das für den Import bzw. den Export zu verwendende Datenmodell und bestimmt damit die Menge der für das Business Entity zur Verfügung stehenden Objekte, Attribute und Beziehungen.
Externes Objekt
Ein externes Objekt ist ein Entwicklungsobjekt, das die ausgewählten und evtl. auch bereits aufgelösten Attribute enthält. Im Controller für den vereinfachten Datenaustausches dient es als „Filter“ wie im klassischen Business Integration Service (BIS). Da es ein Entwicklungsobjekt ist, muss man eine neue Version des Entwicklungsobjekts erstellen, um den „Filter“ zu ändern.
ExternalValueNode
Durch diese externen Knoten wird die externe Struktur abgebildet. Das Objekt ist ein „Wrapper“ um das „Externe Objekt“ und kennt zusätzlich die Struktur, d. h. übergeordnete und untergeordnete andere externe Objekte. Diese Struktur wird durch Registrierungen gebildet.
InternalValueNode
Durch diese internen Knoten wird die interne Struktur abgebildet. Das Objekt ist ein „Wrapper“ um das betroffene „CisObject“. Zusätzlich kennt es die übergeordneten und die untergeordneten Business Objects. Diese Struktur wird durch die ObjectInfo gebildet.
3 Entwicklung
Die durch das Entwicklungsobjekt des Typs „Externes Objekt“ vorgegebene Struktur erlaubt blockweises Lesen und Schreiben der Daten. Dies kann zu einem deutlichen Leistungsgewinn gegenüber dem klassischen Business Integration Service (BIS) führen. Wenn zusätzliche Einzelzugriffe auf die Datenbank bei der Entwicklung des Controllers erfolgen, dann wird dieser Gewinn wieder zunichte gemacht. Beachten Sie deshalb: Sind Einzelzugriffe auf eine Datenbank notwendig, dann ist dies ein Hinweis darauf, dass die Flexibilität des klassischen BIS erforderlich ist. Der vereinfachte Datenaustausch ist dafür nicht sinnvoll einsetzbar.
3.1 Anwendungsobjekte
Voraussetzung für den vereinfachten Datenexport bzw. Datenimport sind Entwicklungsobjekte des Typs „Anwendung“, für die der Anwendungstyp „Vereinfachter Datenaustausch“ und die besondere Verwendung „Export“ bzw. „Import“ festgelegt sind. Diese können in den Anwendungen „Vereinfachter Datenexport“ bzw. „Vereinfachter Datenimport“ ausgewählt werden. Als Java-Klasse muss der Controller angegeben werden.
3.2 Controller
Ein Controller ist eine Java-Klasse, die den Import und Export für ein bestimmtes Business Entity realisiert. Beachten Sie Folgendes:
- Ein Controller für den vereinfachten Datenaustausch muss von der abstrakten Klasse „com.cisag.pgm.bi.lite.LiteController“ abgeleitet sein.
- Soll für ein Business Entity der Export und Import möglich sein, aber der Import nur einen Ausschnitt des Datenmodells des Exports umfassen, dann implementieren Sie den Import- und den Export-Controller in zwei verschiedenen Klassen, um ein unterschiedliches Datenmodell angeben zu können.
3.2.1 ObjectInfo
Jeder Controller definiert das BIS-Datenmodell, das beim Import bzw. Export verwendet wird. Beim vereinfachten Datenaustausch hat die „ObjectInfo“ zwei Aufgaben:
- Wenn durch den Import ein neues Objekt erzeugt werden soll, dann wird die Gesamtmenge der zu erzeugenden Business Objects bestimmt. Hierzu ist zusätzlich die Registrierung eines „Vorlageobjekts“ notwendig.
- Wenn man eine komplexere Struktur aufbauen möchte und mehrere „Externe Objekt“ verkoppelt, dann erfolgt die Verkopplung über eine in der „ObjectInfo“ festgelegte Beziehung.
Das BIS-Datenmodell gibt die Struktur der importierten bzw. exportierten Daten vor.
Hinweis:
Typischerweise existiert bereits der klassische BIS für ein Business Entity. Der klassische BIS muss ebenfalls eine ObjectInfo festlegen. Daher ist am einfachsten diese bereits festgelegte ObjectInfo auch für den vereinfachten Datenaustausch zu verwenden. Weitere Informationen u. a. zu den Besonderheiten bei der Erstellung der ObjectInfo finden Sie in der Dokumentation „Referenzhandbuch: Datenaustausch“.
3.2.2 Registrierungen
3.2.2.1 Externe Struktur
Im klassischen BIS sind Filter vorhanden, aus dem man die verwendeten Attribute auswählen kann. Der vereinfachte Datenaustausch benötigt eine festgelegte Struktur der Daten. Diese Festlegung erfolgt über ein „Externes Objekt“ (Entwicklungsobjekttyp).
In der konkreten Implementierung eines Controllers für den vereinfachten Datenaustausch müssen Sie die abstrakte Methode „registerExternalInformation“ ändern. Darin müssen Sie bestimmte Informationen für den vereinfachten Datenaustausch festlegen.
Beispiel für einen einfachen Fall dieser Methode:
@Override
protected boolean registerExternalInformation() {
return registerExternalObjectByBusinessKey(ExternalItem.class);
}
In diesem Beispiel wird das externe Objekt „ExternalItem“ als Hauptobjekt registriert. Dieses externe Objekt bezieht sich auf des Business Object „Item“. Gleichzeitig wird festgelegt, dass der „Business Key“ verwendet werden soll.
Folgende Methoden stehen Ihnen zur Registrierung des Hauptobjekts zur Verfügung:
- registerExternalObjectByPrimaryKey
- registerExternalObjectByBusinessKey
- registerExternalObjectBySecondaryKey
Empfohlen wird die Registrierung über den „Business Key“. Pro Controller darf nur ein externes Objekt als Hauptobjekt registriert werden, d. h. es muss in genau eine dieser Methoden genau einmal aufgerufen werden.
Sie können auch komplexere externer Strukturen aufbauen. Was möglich ist, wird durch die bereits festgelegte ObjectInfo vorgegeben.
Um zusätzliche „Kind“-Objekte zu registrieren verwenden Sie z. B. Folgendes:
@Override
protected boolean registerExternalInformation(){
boolean result = registerExternalObjectByBusinessKey(ExternalItem.class);
AssociationDescriptor purchaseItemsAssociation = getObjectInfo().getAssociation(“PurchaseItems”);
result &= registerExternalChildByPrimaryKey(ExternalItem.class,purchaseItemsAssociation , ExternalPurchaseItem.class);
return result;
}
In diesem Beispiel wird zuerst wie oben ein externes Objekt „ExternalItem“ über den Business-Key registriert. Zwischen dem Business Object „Item“ und „PurchaseItem“ ist über die ObjectInfo eine Association definiert. Diese kann verwendet werden, um das externe Objekt „ExternalPurchaseItem“ als „Kind“ des externen Objekts „ExternalItem“ zu registrieren.
Das externe Objekt „ExternalPurchaseItem“ bezieht sich auf das Business Object „PurchaseItem“. In diesem Fall erfolgt die Registrierung des „PrimaryKey“. Die Beziehung zielt auf den „PrimaryKey“ des Business Objects „PurchaseItem“.
Als erster Parameter wird das „Eltern“-Externe-Objekt angegeben, dann die Beziehung (Association) zwischen den Objekten und dann das „Kind“-Externe-Objekt. Das Eltern-Objekt muss bereits registriert sein, um hierfür „Kind“-Objekte registrieren zu können.
Um „Kind“-Objekte zu registrieren stehen Ihnen folgende Methoden zur Verfügung.
- registerExternalChildByPrimaryKey
- registerExternalChildByBusinessKey
- registerExternalChildBySecondaryKey
Über dieselben Methoden können Sie auch „Kindes-Kind“-Objekte an bereits registrierte „Kind“-Objekt registrieren.
3.2.2.2 Vorlagenobjekt
Sie können einige weitere Registrierungen vornehmen. Am wichtigsten ist diese Methode: registerTemplateKey(byte[] key)
Hiermit können Sie ein Business Object auszeichnen, das als Vorlage beim Import verwendet werden soll. Die externe Struktur ist typischerweise nur ein kleiner Ausschnitt aus der über die ObjectInfo festgelegte Maximalmenge an Objekten und den darin enthaltenen Attributen. Importiert werden nur die über die externe Struktur und die hierfür verwendeten externen Objekte festgelegten Daten. Dies ist aber meist nicht ausreichend.
Beispiel:
Die externe Struktur enthält nur Daten aus den Business Object „Item“ und „PurchaseItem“, dargestellt über die zugehörigen externen Objekte. Um einen Artikel verwenden zu können, sind jedoch noch Rechnungswesendaten nötig. Hierfür dient das Vorlagenobjekt. Da in diesem Beispiel „Item“ das Hauptobjekt ist, registrieren Sie einen Artikel als Vorlagenobjekt. Wenn beim Import festgestellt wird, dass hierfür keine Instanz existiert, dann wird eine Kopie des Vorlagenobjekts erzeugt und die externen Daten auf diese Kopie übertragen. Natürlich müssen alle eindeutigen Schlüssel aller so kopierten Objekte geändert werden. Sind diese Schlüsselattribute vom Datentyp „Guid“, dann geschieht das automatisch. Alle eindeutigen Schlüssel aller beteiligten Business Objects müssen in der Kopie des Vorlagenobjekts entweder automatisch oder über die externe Struktur geändert werden. Ansonsten gäbe es unweigerlich eine „DuplicateKeyViolation“.
Beispiel:
@Override
protected boolean registerExternalInformation(){
…
registerTemplateKey(Item.buildByNumberKey(“ABCDE”));
…
}
Wenn beim Import festgestellt wird, dass der zu importierende Artikel noch fehlt, dann wird der Artikel „ABCDE“ als Vorlage verwendet. Stellen Sie organisatorisch sicher, dass der Artikel „ABCDE“ tatsächlich besteht. Technisch wird eine Kopie des Vorlagenartikels erzeugt. Dies beinhaltet alle in ObjectInfo angegebenen Business Objects.
Sie können auch mehrere Vorlagenobjekte registrieren und dann selbst entscheiden, welches Sie im konkreten Fall ändern möchten. Hierfür ändern Sie diese Methode:
protected InternalValueNode getTemplate(ExternalValueNode vn)
Sollte genau ein Vorlagenobjekt registriert sein, dann ist dies nicht nötig. In dem Fall wird immer dieses zurückgeliefert.
Sollten Sie kein Vorlagenobjekt registrieren, dann kann das System über den Import keine neuen Objekte erzeugen. In der Anwendung „Vereinfachter Datenimport“ erhalten Sie in diesem Fall eine entsprechende Warnmeldung.
3.2.2.3 FormatLookup
So wie beim klassischen Business Integration Service (BIS) kann ein FormatLookup für ein Attribut registriert werden. Dies ist zum Beispiel sinnvoll, wenn die Darstellung eines Werts eines Attributs abhängig vom verwendeten Dateiformat ist.
3.2.2.4 Standardauflösungen
Im Entwicklungsobjekt des Typs „Externes Objekt“ können Auflösungen festgelegt werden. Das externe Objekt enthält ein Attribut, das eigentlich ein Fremdschlüssel ist. Im externen Objekt können Sie über die Beziehung zum Business Object festlegen, aus dem der Fremdschlüssel stammt, ob und wie dieser Fremdschlüssel aufgelöst werden soll. Typischerweise ist ein Fremdschlüssel der PrimaryKey des Zielobjekts. Lesbarer ist jedoch der BusinessKey.
Beispiel:
Das Business Object „ItemCountryData“ ist vom Typ „Dependent” und gehört zum Business Object „Item“. Der Primärschlüssel des Dependent ist zweiteilig: ein Attribut zeigt auf das Business Object „Item“, das andere auf das Business Object „Country“. In der Artikel-Anwendung ist festgelegt, dass ein übergreifender Datensatz „ItemCountryData“ besteht, der gilt, falls keine spezifischen Länderdaten existieren. Dieser übergreifende Datensatz hat den Schlüsselwert ZEROGUID für das Attribute „country“. Eine Business-Object-Instanz für „Country“ mit dem Schlüssel ZEROGUID fehlt jedoch. Somit würde die Fremdschlüsselauflösung in diesem Fall fehlschlagen.
Wenn also ein Schlüssel nicht auflösbar ist, dann wird Folgendes automatisch überprüft:
- Ist das Attribut selbst Teil des Primärschlüssels?
- Ist das Attribut vom Datentyp „guid“?
- Ist im Fall des Exports der Wert gleich ZEROGUID?
- Ist im Fall des Imports als Wert für das BusinessKey-Attribut ein Leerstring oder null in der Importdatei vorhanden?
Sowohl beim Export als auch beim Import interessiert die konkrete Instanz des Business Objects „Country“ nicht. Nur die Auflösung PrimaryKey nach BusinessKey wird benötigt. Wenn also die oben genannten Bedingungen zutreffen, dann wird intern im Speicher die Auflösung ohne eine konkrete Instanz ausgeführt.
Bestehen Fälle abweichend von diesem Muster und soll dennoch eine Schlüsselauflösung erfolgen, dann können Sie per Registrierung eingreifen:
registerDefaultResolving
Als Parameter müssen Sie das externe Objekt, den darin festgelegten Namen des Fremdschlüsselauflösers, den Wert des Fremdschlüssel-Attributs und den auflösenden Wert angeben. Wenn ein Datensatz diesen Bedingungen entspricht, dann wird diese Registrierung zu Auflösung verwendet.
Hiermit kann man auch das oben beschriebene Standardverhalten ändern.
Beispiel
@Override
protected boolean registerExternalInformation(){
…
registerDefaultResolving(ExternalItemCountryData.class, “country”, Guid.ZEROGUID, “ZEROGUIDSTRING”);
…
}
In dem Fall wird im externen Objekt „ExternalItemCountryData“ der Fremdschlüsselauflöser „country“ behandelt. Falls der konkrete Wert gleich „Zeroguid“ ist, dann wird in die exportierte Datei für das auflösende Attribut der Wert „ZEROGUIDSTRING“ geschrieben.
Beim Import wird umgekehrt vorgegangen: Wird in einer zu importierenden Datei für das auflösende Attribut der Wert „ZEROGUIDSTRING“ gefunden, dann wird für den konkreten Wert des Fremdschlüssel-Attributs „Zeroguid“ angenommen. Das oben beschriebene Standardverhalten wird so verändert.
Für komplexere Schlüssel besteht eine zweite Signatur. Darin werden dann die Werte als zwei Listen übergeben.
3.2.2.5 Zusätzliche Objekte laden
Der Leistungsvorteil des vereinfachten Datenaustausches liegt am blockweisen Lesen und Schreiben der Daten. Wenn Konsistenzprüfungen für die importierten Daten durchgeführt werden müssen (siehe Kapitel „Prüfungen“) und hierfür Daten benötigt werden, die in den Importdateien nicht vorhanden sind, dann kann man hiermit dafür sorgen, dass diese Daten auch gleich blockweise gelesen werden.
Beispiel:
@Override
protected boolean registerExternalInformation(){
…
registerAdditionalObjectToBeLoaded(ItemAccountingData.class);
…
}
In diesem Beispiel werden Beschaffungsdaten mit Rechnungswesendaten geprüft. Gleichzeitig sind die Rechnungswesendaten nicht Teil des Imports. Die Voraussetzung ist, dass das angefragte Business Object ein Teil der ObjectInfo ist.
Rein technisch ist diese Art der Registrierung nicht nötig, Sie können so aber unter Umständen die Leistung verbessern.
3.2.3 Prüfungen
Durch die Implementierung des Controllers übernehmen Sie die Verantwortung für die Konsistenz importierter Daten. Einige rein technische Prüfungen werden automatisch durchgeführt. Wenn Sie per Import existierende Daten ändern, dann dürfen eindeutige Schlüssel nicht geändert werden.
Wenn Sie das System per Import neue Daten erzeugen lassen, dann liegt der genau gegenteilige Fall vor. Automatisch wird dann geprüft, ob auch jeder eindeutige Schlüssel gegenüber dem Vorlageobjekt geändert wurde.
Durch die Implementierung der Methode validateImport können Sie weitere Prüfungen durchführen. Sollten ein Fehler eindeckt werden, dann können Sie die Daten mit „invalid“ kennzeichnen.
3.2.4 Abbruch bzw. Weitermachen
Die Daten werden blockweise behandelt. Wenn in unter den importierten Daten fehlerhafte Datensätze gefunden werden, dann werden diese normalerweise einfach übersprungen und nur die korrekten Daten gespeichert.
Sie können jedoch durch Ändern der Methode handleImportErrors entscheiden, ob ein Abbruch erfolgen soll oder fehlerhafte Datensätze gesondert zu protokollieren sind.