1 Themenübersicht
Das ERP-System stellt Schnittstellen zur konfliktfreien Erweiterung von Anwendungen zur Verfügung. Die Konfliktfreiheit basiert darauf, dass Erweiterungen nur aus neuen Entwicklungsobjekten bestehen und keine existierenden Entwicklungsobjekte verändert werden müssen. Damit gibt es keine Konflikte beim Aktualisieren eines Entwicklungssystems. Die konfliktfreie Erweiterbarkeit von Anwendungen ist auch eine Voraussetzung für die App-Technologie.
Die Schnittstellen für die Erweiterung sind Objektsichten, Hooks, die anpassbare Oberfläche sowie einige weitere Entwicklungsobjekttypen. In diesem Dokument wird die Bereitstellung der Schnittstellen in Anwendungen, als auch die Nutzung der Schnittstellen, um Anwendungen zu erweitern, beschrieben.
2 Zielgruppe
Entwickler
3 Begriffsbestimmung
Modul
Ein Modul beinhaltet die Entwicklungen aus einem Adaptierungssystem oder einer App. Während die Entwicklungen des Adaptierungssystems ein Modul bilden, ist jede App ein eigenes Modul, auch bei mehreren Apps, die aus demselben App-Entwicklungssystem stammen.
4 Objektsichten
Eine Objektsicht ist eine Schnittstelle auf Daten eines Business Entitys, das in einer Anwendung bearbeitet oder verwendet wird. Die Objektsicht wird verwendet, um Daten des Business Entitys als Felder in der anpassbaren Oberfläche einer Anwendung darzustellen und sie als Parameter in Hooks zur Verfügung zu stellen.
Eine Objektsicht kann in einer Adaptierung oder einer App durch Extensions und Objektsicht-Erweiterungen erweitert werden.
Jede Objektsicht basiert auf einem Business Object. Sie enthält Attribute und Beziehungen des Business Objects. Die Attribute und Beziehungen können jedoch auch vom Business Object abweichen.
Für jede Objektsicht werden zwei Java-Interfaces, View und Access, erzeugt. Der View enthält alle lesenden Methoden sowie Enums mit den Attributen und Beziehungen. Der Access enthält zusätzlich schreibende Methoden auf Erweiterungsattribute und –beziehungen. Weiterhin gibt es den FullAccess mit schreibenden Methoden für alle Attribute und Beziehungen. Der FullAccess wird als Inner-Interface im Access erzeugt.
Beispiel: Aus einer Objektsicht com.cisag.app.sales.model.DeliverySlipType werden die Interfaces com.cisag.app.sales.model.DeliverySlipTypeView und com.cisag.app.sales.model.DeliverySlipTypeAccess erzeugt.
4.1 Objektsichten als Entwicklungsobjekte
4.1.1 Attribute und Beziehungen
Eine Objektsicht wird durch eine XML-Datei beschrieben. In der XML-Datei muss mindestens das Business Object und eine Implementierungsklasse (DataObject) angegeben werden. Dies zeigt das folgende Beispiel einer Objektsicht zum Business Object „Liefer-Auftragsart“:
<?xml version=”1.0″ encoding=”UTF-8″?>
<dataview xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:noNamespaceSchemaLocation=”DataViewXMLSchema.xsd”>
<object>com.cisag.app.sales.obj.DeliverySlipType</object>
<implementation>com.cisag.app.general.log.SingleObjectDataObject
</implementation>
</dataview>
Im XML der Objektsicht werden Attribute und Beziehungen nur angegeben, wenn der Entwickler für sie besondere Einstellungen angeben möchte. Im Beispiel sind im XML keine Attribute oder Beziehungen angegeben, so dass die Objektsicht zur Laufzeit (d.h. in der anpassbaren Oberfläche) alle Attribute und Beziehungen des Business Objects vorhanden und auch schreibbar sind. Ausnahmen hierzu sind Primary- und Business-Key-Attribute, die nur lesbar sind. Weitere Ausnahmen für einige technische Attribute sind im Dokument „Objektsichten“ beschrieben.
Attribute aus der Objektsicht können ausgeblendet oder der Zugriff auf die Lesbarkeit eingeschränkt werden. Ausblenden bzw. Nur-Lese-Zugriff wirken sich sowohl auf die anpassbare Oberfläche als auch auf den programmierten Zugriff aus.
Virtuelle Attribute und Beziehungen sind solche, die im Business Object nicht vorhanden sind. Damit können beispielsweise Attribute definiert werden, deren Werte sich durch Berechnungen ergeben. Virtuelle Attribute und Beziehungen müssen zusätzlich im DataObject implementiert werden, wie im nächsten Abschnitt beschrieben.
Das folgende Beispiel zeigt ein ausgeblendetes Attribut und eine virtuelle Beziehung, die auf eine Objektsicht zeigt:
<attribute property=”EXCLUDED”>
<name>pickingNumberRange</name>
</attribute>
<virtualrelation property=”MUTABLE” cardinality=”ONE_ONE”>
<name>CommonItemCountryData</name>
<targetview>com.cisag.app.general.item.model.ItemCountryData
</targetview>
</virtualrelation>
(Das Attribut im Beispiel stammt aus der Objektsicht „Liefer-Auftragsarten“, die virtuelle Beziehung hingegen aus der Objektsicht „Artikel“.)
Die Angaben im Beispiel haben folgende Auswirkungen auf die generierten Interfaces:
- Für das ausgeblendete Attribut wird ein kein Getter im View, und kein Setter im FullAccess
- Für die 1:1-Beziehung wird eine retrieve-Methode im View generiert.
4.1.2 DataObject
Das DataObject einer Objektsicht ist eine Java-Klasse und enthält die Implementierung virtueller Attribute und Beziehungen sowie den Zugriff auf mehrsprachige Attribute. Falls in der Objektsicht keine dieser Besonderheiten vorkommen, dann reicht in der Objektsicht die Klasse com.cisag.pgm.base.DataObject anzugeben. Anderenfalls muss diese Klasse abgeleitet werden.
Hinweis:
Für SingleObjectEntitys sollte als DataObject die Klasse SingleObjectDataObject angegeben oder als Basisklasse verwendet werden.
Das folgende Beispiel enthält die Implementierung der virtuellen Beziehung aus dem obigen Beispiel:
public DataObject<ItemCountryData> retrieveCommonItemCountryData() {
return new ItemCountryDataDataObject(…);
}
Bei der Implementierung von retrieve-Methoden für 1:n-Beziehungen muss ein Objekt der Klasse com.cisag.pgm.base.OneMany zurückgegeben werden.
Diverse Implementierungen des One-Many-Interfaces erleichtern die Verwen-dung:
- Die Klasse cisag.pgm.util.OneManyBase ist die Basis-Klasse für eigene Implementierungen des One-Many-Interfaces.
- Die Klasse cisag.pgm.util.OneManyObjectIterator implementiert ein One-Many-Objekt auf den Ergebnissen eines ObjectIterators.
- Die Klasse cisag.pgm.util.OneManyCollection implementiert ein One-Many-Objekt auf einer Collection von CisObject.
Weitere Information und Beispiele für 1:n Beziehungen finden Sie in der Dokumentation „Objektsichten“.
Ein Zugriff auf mehrsprachige Attribute kann im DataObject auf zwei Arten implementiert werden: Zum einen mit einer generischen Methode com.cisag.pgm.base.DataObject.GenericNLS.getNLSData(String), oder je Attribut mit einer get…$NLS-Methode, wie das folgenden Beispiel zeigt.
public NLSData getDescription$NLS() {
NLSData nlsDescription;
if (isApplicationContext()) {
nlsDescription = getRoleEntity().getNlsDescription();
} else {
nlsDescription = new NLSData(
“com.cisag.app.general.obj.Item:description”);
Item item = getObject();
if (item == null) {
nlsDescription = “”;
} else {
nlsDescription.load(item.is_transient() ?
CisEnvironment.getInstance().getObjectManager().getObject(
Item.buildPrimaryKey(item.getGuid())) : item);
}
}
return nlsDescription;
}
Hinweis für SingleObjectEntity:
Die Klasse SingleObjectDataObject enthält eine Implementierung der Methode getNLSData für alle mehrsprachigen Attribute des Business Objects.
4.1.3 View-Interface
Sie können im XML mit „viewinterface“ und „accessinterface“ die erzeugten View- bzw. Access-Interfaces um eigene Interfaces erweitern. Die Angaben sind optional.
<viewinterface>
com.cisag.app.general.model.SingleObjectViewInterface
</viewinterface>
Ein solches Interface kann genutzt werden, um Gemeinsamkeiten mehrerer Objektsichten in einem Interface abzubilden, oder um dem erzeugten View bzw. Access weitere Methoden hinzuzufügen. Solche zusätzlichen Methoden müssen im DataObject mithilfe Methoden gleicher Signatur wie im Interface implementiert werden.
Beispiel:
In View-Interfaces wird oft der Zugriff auf einen Zustandsbehafteten Hook definiert und entsprechend im DataObject implementiert. Näheres hierzu ist in Abschnitt 5.1.2 beschrieben.
Hinweis:
Für SingleObjectEntity sollte com.cisag.app.general.model.SingleObjectViewInterface oder eine Erweiterung dieses Interface als „viewinterface“ verwendet werden.
4.1.4 Generierung
Die Java-Interfaces werden bei Änderungen der zugrunde liegenden Business Objects und Extensions durch den Toolshell-Befehl crtbo neu erzeugt. Bei Änderungen nur in der Objektsicht oder einer Objektsicht-Erweiterung werden sie durch den Toolshell-Befehl crtdv neu erzeugt.
4.2 Objektsichten in komplexen Entitys
Bei Business Entitys, die aus mehreren Business Objects bestehen, wird in der Regel für jedes Business Object eine eigene Objektsicht erfasst und die Objektsichten sind untereinander durch Beziehungen verknüpft. Dazu wird im XML der Objektsicht eine Beziehung mit Zieltyp „Objektsicht“ verwendet.
<relation property=”MUTABLE” cardinality=”ONE_ONE”>
<name>CommonItemCountryData</name>
<targetview>com.cisag.app.general.item.model.ItemCountryData
</targetview>
</relation>
Beziehungen, die das Business Entity verlassen, verwenden demgegenüber in der Regel den Zieltyp „Business Object“.
4.3 Extensions und Objektsicht-Erweiterungen
Um ein Business Entity um neue Attribute zu erweitern, die als Felder in der anpassbaren Oberfläche verfügbar sind, kann eine Extension oder eine Objektsicht verwendet werden. Mit einer Extension fügen Sie persistente Attribute hinzu, während mit einer Objektsicht-Erweiterung virtuelle Attribute hinzugefügt oder Extension-Attribute verändert werden können. Beziehungen können ebenfalls hinzugefügt werden.
Attribute und Beziehungen in einer Extension oder Objektsicht-Erweiterung verwenden einen Präfix im Namen, um die notwendige Eindeutigkeit sicherzustellen:
- Außerhalb von Apps wird der Entwicklungspräfix des Systems („xyz“ im Beispiel) verwendet:
- Attribut: xyz_description
- Beziehung: Xyz_Description
- In Apps wird zusätzlich der App-Name verwendet:
- Attribut: xyz_appname_description
- Beziehung: Xyz_Appname_Description
Wenn für Extension-Attribute und –Beziehungen keine Änderungen in einer Objektsicht-Erweiterung nötig sind, so müssen Sie keine Objektsicht-Erweiterung erfassen.
Im folgenden Beispiel wird mithilfe einer Objektsicht-Erweiterung die Beziehung „Ado_Simple_SingleDependent“ geändert, so dass Zielobjekt dieser Beziehung kein Business Objekt sondern eine Objektsicht ist:
<?xml version=”1.0″ encoding=”UTF-8″?>
<dataviewextension xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=”DataViewExtensionXMLSchema.xsd”>
<!– Don’t change this line and the lines above! –>
<dataview>com.cisag.app.sales.model.DeliverySlipType</dataview>
<implementation>
com.ado.ext.app.simple.sales.log.DeliverySlipTypeDataExtension
</implementation>
<relation property=”MUTABLE”>
<name>Ado_Simple_SingleDependent</name>
<targetview>
com.ado.ext.app.simple.common.model.SingleDependent
</targetview>
</relation>
</dataviewextension>
Methoden für mehrsprachige Attribute, und virtuelle Attribute und Beziehungen werden in einer Unterklasse der Klasse com.cisag.pgm.base.DataExtension implementiert. Diese Klasse wird im XML als „implementation“ angegeben.
Für das Beispiel muss eine retrieve-Methode implementiert werden:
public DataObject<SingleDependent> retrieveAdo_Simple_SingleDependent() {
SimpleState state = (SimpleState) getView().getHookState();
return state.getSingleDependent() != null ?
new DataObject<SingleDependent>(state.getSingleDependent()) :
null;
}
Für mehrsprachige Attribute kann in der DataExtension nur die Möglichkeit der get…$NLS-Methode genutzt werden.
Hinweis:
Das Implementieren von get…$NLS-Methoden ist beim SingleObjectEntity nicht notwendig, da, wie oben beschrieben, die Klasse SingleObjectDataObject eine generische Implementierung für mehrsprachige Attribute besitzt.
5 Hooks
Hooks dienen zum konfliktfreien Erweitern von Programmcode im ERP-System. Zur Erweiterbarkeit wird ein Java-Interface (Hook) definiert, und die Methoden des Interfaces werden zu bestimmten Zeitpunkten aufgerufen. Der erweiterbare Programmcode ist damit Hook-Anbieter. Die verfügbaren Hooks sind durch Entwicklungsobjekte des Typs „Hook Contract“, Subtyp „Hook Contract Definition“ beschrieben.
Erweitert wird der Programmcode durch das Implementieren des Interfaces und der Registrierung dieser Hook-Implementierung. Die Registrierung von Hook-Implementierungen erfolgt durch ein Entwicklungsobjekt des Typs „Hook Contract“, Subtyp „Hook Contract Implementierung“.
Die Schnittstelle, die ein Hook anbietet, hat einen klar definierten Funktionsumfang. Die Daten eines Business Entitys werden normalerweise als Objektsichten zur Verfügung gestellt. Die Objektsichten enthalten nur die öffentlichen Daten eines Business Entity, aber keine internen Daten oder Operationen.
Hook-Implementierungen können normalerweise keinen Einfluss auf die Abläufe in einer Anwendung nehmen.
Zur Erweiterung von Anwendungen werden zwei Arten von Hooks angeboten:
- Sie können mit Business-Entity-bezogenen Hooks bestehende Business-Entitys um neue Daten wie beispielsweise neue Felder erweitern.
Siehe Abschnitt „Business-Entity-bezogene Hooks“
- Sie können mit Anwendungs-bezogenen Hooks bestehende Anwendungen um neue Funktionen erweitern bzw. existierende Funktionen ändern.
Siehe Abschnitt „Anwendungs-bezogenene Hooks“
5.1 Business-Entity-bezogene Hooks
In diesem Abschnitt werden Business-Entity-bezogene Hooks am Beispiel des Business Entitys „Liefer-Auftragsarten“ gezeigt, dass die SingleObjectEntity-Klassenstruktur benutzt. Für dieses Business Entity sind die Business-Entity-bezogenen Hooks in der Hook-Contract-Definition com.cisag.app.sales.delivery.hook.log.DeliverySlipType enthalten.
Die Hook-Contract-Definitionen enthält zustandslose Hooks für unterschiedliche Aspekte des Business Entitys wie Prüfungen, Default-Werte usw. Bei zustandslosen Hooks wird eine Hook-Implementierung normalerweise nicht über einen längeren definierten Zeitraum wiederverwendet und sie kann damit keinen Zustand halten.
Die Hook-Contract-Definition enthält einen zustandsbehafteten Hook, der eine klar definierte Lebensdauer hat und damit einen Zustand halten kann.
5.1.1 Zustandslose Hooks implementieren
Für die Funktionshooks wird im Folgenden die Implementierung der für die Unterstützung von Extension-Attributen nötigen Hooks beschrieben. Für Vorschlagswerte und Prüfungen der Extension-Attribute dieses Business Entitys werden die Hooks „ApplyDefaults“ und „ValidateUpdate“ implementiert. Beide Hooks können in derselben Java-Klasse implementiert werden.[1]
public class DeliverySlipTypeHookImpl implements
SingleObjectValidateUpdateHook<DeliverySlipTypeView>,
SingleObjectApplyDefaultsHook<DeliverySlipTypeAccess.Full> {
…
@Override
public void applyDefaults(DeliverySlipTypeAccess.Full dataFullAccess)
{
dataFullAccess.setAdo_simple_value(“an example value”);
}
@Override
public void validateUpdate(DeliverySlipTypeView dataView) {
mm.setProgramMessageDataViewPath(Attribute.$ado_simple_value);
String wrong = “X”;
if (!CisStringUtility.isEmpty(dataView.getAdo_simple_value())
&& dataView.getAdo_simple_value().startsWith(wrong)) {
mm.sendMessage(“ADO_SIMPLE”, 1,
dataView.getAdo_simple_value(), wrong);
}
}
}
Die Hooks werden mit folgender Hook-Contract-Implementierung registriert:
<?xml version=”1.0″ encoding=”UTF-8″?>
<HookContract xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=”HookXMLSchema.xsd”>
<HOOK_IMPLEMENTATION>
<contract>com.cisag.app.sales.delivery.hook.log.DeliverySlipType
</contract>
<hook>
<interface>
com.cisag.app.general.hook.log.SingleObjectApplyDefaultsHook
</interface>
<implementation>
com.ado.ext.app.simple.sales.delivery.log.DeliverySlipTypeHookImpl
</implementation>
</hook>
<hook>
<interface>
com.cisag.app.general.hook.log.SingleObjectValidateUpdateHook
</interface>
<implementation>
com.ado.ext.app.simple.sales.delivery.log.DeliverySlipTypeHookImpl
</implementation>
</hook>
</HOOK_IMPLEMENTATION>
</HookContract>
Die Methode validateUpdate() sorgt durch das Senden der Fehlermeldung dafür, dass im Fehlerfall die gesamte Lieferauftragsart nicht gespeichert werden kann, und der Benutzer den Fehler zunächst korrigieren muss. Die verwendete Meldungszuordnung (setProgramMessageDataViewPath) ist in Abschnitt 6.6 beschrieben.
5.1.2 Zustandsbehaftete Hooks implementieren
Bei bestimmten Arten von Erweiterungen ist notwendig, dass die Erweiterung einen Zustand verwalten kann. Ein Zustand beinhaltet beispielsweise transiente Daten eines Dependent, bevor dieser gespeichert wird. Ein Zustand wird in einem Zustandshook gehalten. Unter den Business-Entity-bezogenen Hooks wird in der Regel auch ein zustandsbehafteter Hook angeboten.
Zustandsbehaftete Hooks werden immer zusammen mit zustandslosen Hooks verwendet. Sie werden entweder als Parameter oder als Bestandteil der Objektsicht an Methoden des zustandslosen Hooks übergeben. Falls in einer Hook-Contract-Implementierung ein Zustandshook nicht implementiert wird, ist der zustandsbehaftete Hook beim Aufruf null.
In der Hook-Contract-Implementierung wird zum vorigen Beispiel Folgendes ergänzt, um einen zustandsbehafteten Hook zu implementieren:
<hookState>
<interface>
com.cisag.app.general.hook.log.SingleObjectEntityState
</interface>
<implementation>
com.ado.ext.app.simple.common.log.SimpleState
</implementation>
</hookState>
Eine Hook-Methode kann dann wie im folgenden Beispiel auf die eigene Implementierung des Zustandshooks zugreifen:
public void validateUpdate(DeliverySlipTypeView dataView) {
SimpleState state = (SimpleState) dataView.getHookState();
CisObjectContainer<MultipleDependent> multipleDependentContainer =
state.getMultipleDependentContainer();
…
}
Die XML- und Javacode-Ausschnitte sind dem Beispiel für komplexe GUI-Komponenten in Abschnitt 6.8 entnommen.
5.2 Anwendungs-bezogene Hooks
Die in diesem Abschnitt beschrieben Hooks ermöglichen die Erweiterung von Anwendungen in anderen Aspekten als der anpassbaren Oberfläche.
5.2.1 Locatorsuchen
Hook-Contract-Definition com.cisag.pgm.base.CisUiApplication
Hook com.cisag.pgm.search.hook.LocatorSearchHook
Mit diesem Hook ist möglich, einer Anwendung neue Suchen in den Navigationsbereich hinzuzufügen. Suchen können wahlweise vor oder hinter den vorhandenen Suchen eingefügt werden.
Eine hinzugefügte Suche muss mit den Anwendungsparametern kompatibel sein, damit Sie mithilfe der Suche Objekte in der Anwendung öffnen können.
5.2.2 Anwendungsparameter
Hook-Contract-Definition com.cisag.pgm.appserver.Server
Hook com.cisag.pgm.appserver.hook.EntityMenuRegistryHook
Mit diesem Hook können einer Anwendung neue Parameter des Typs „Business Entity“ hinzugefügt werden, so als seien die Parameter im Entwicklungsobjekt „Anwendung“ erfasst. Aus den hinzugefügten Parametern entstehen automatisch Einträge für das Kontextmenü eines Business-Entity-Feldes.
Hinzugefügte Anwendungsparameter müssen mit der Implementierung der Anwendung kompatibel sein (Methode CisUiApplication#run()). Dieser Hook ist beispielsweise für die Anwendung „Klassifikationen“ nützlich.
5.2.3 Anwendungsaktionen
Hook-Contract-Definition com.cisag.pgm.datatype.BusinessEntity
Hook com.cisag.pgm.datatype.hook.
BusinessEntityMaintenanceApplicationHook
Mit diesem Hook können in bestimmten Anwendungen die Aktionen Speichern und Löschen in der Standard-Symbolleiste deaktiviert werden. Der Hook kann verwendet werden, wenn Erweiterungen eigene Anwendungen zur Bearbeitung von Business Entitys aus dem Standard verwenden und diese Business Entitys nicht in den für die Bearbeitung vorgesehenen Standard-Anwendungen gespeichert oder gelöscht werden sollen.
6 Die anpassbare Oberfläche
Anwendungen, die die anpassbare Oberfläche und Objektsichten unterstützen, können einfach um neue Felder erweitert werden. Die Felder einer dieser anpassbaren Anwendung werden durch die Attribute einer Objektsicht beschrieben. Objektsichten können durch Objektsicht-Erweiterungen und Extensions auf jedem System nachträglich erweitert werden. Neue Felder, die auf diese Art hinzugefügt wurden, stehen in der anpassbaren Oberfläche zur Verfügung.
6.1 Anpassbare Anwendungen und Designmodus
Für eine anpassbare Anwendung muss im Entwicklungsobjekt „Anwendung“ der Typ „Dialog“ und als besondere Verwendung „Anpassbare Anwendung“ eingestellt sein.
Der Designmodus einer erweiterbaren Anwendung dient dazu, Felder verschieben zu können, und Felder aus Erweiterungen in die Oberfläche der Anwendung hinzuzufügen.
Die Benutzung des Designmodus ist an folgende Berechtigungen geknüpft:
- cisag.sys.gui.ChangeLayouts
Mit dem Designmodus eigene Designs verändern
- cisag.sys.gui.ChangeLayoutsForAllUsers
Mit dem Designmodus Designs für alle Benutzer zu verändern
6.2 DataViewUI in der Anwendung
Wenn Sie eine neue anpassbare Anwendung programmieren möchten, die auf einer Objektsicht basiert, müssen Sie Folgendes beachten: Die Objektsicht, die die bereitzustellenden Attribute enthält, muss in die Anwendung mithilfe der Klasse DataViewUI eingebunden sein.
In der init-Methode der Anwendung muss das DataViewUI-Objekt erzeugt werden. Im folgenden Beispiel werden der Identifikationsbereich (Ident-Pane) und der Arbeitsbereich (Work-Pane) der Anwendung als oberste Container für anpassbare Bereiche festgelegt.
dataViewUI = (DataViewUI<DataView<T>>) DataViewUI.create(this,
dataViewClass);
dataViewUI.register(getIdentPane());
dataViewUI.register(getWorkPane());
Ein vollständiges Beispiel folgt weiter unten.
Hinweis:
Für eine SingleObjectMaintenance müssen Sie beachten, dass wenn SingleObjectEntity#getDataViewClass() eine Objektsicht-Klasse zurückgibt, dann wird ein DataViewUI automatisch in der init-Methode erzeugt, und Ident-Pane und Work-Pane registriert. Das Verhalten lässt sich in der Methode initDataViewUI() ändern. SingleObjectEntity unterstützt von sich aus eine Objektsicht pro Anwendung.
Innerhalb der am DataViewUI registrierten Container sind Bereiche anpassbar, für die die folgenden Bedingungen gelten:
- Der Container verwendet StandardLayout.
- Der Container darf geschachtelt in anderen Containern vorkommen, auch z. B. im TabbedPane.
- Der Container muss eine Identifizierung über seine Element-GUID und einem optionalen Komponentennamen besitzen.
- Der Elementbaum mit den anpassbaren Containern muss am Ende der init-Methode vollständig aufgebaut sein und anpassbare Container und ihre Felder dürfen nicht nachträglich entfernt werden.
- Anwendungen mit Ansichten müssen als Unteranwendungen (SubApplication) implementiert werden.
Anwendungen können die Felder ganz oder teilweise automatisch durch die anpassbare Oberfläche erzeugen lassen. Dies muss am DataViewUI eingestellt werden (Methoden setAttributesVisible(…)).
Felder, die die Anwendung selbst erzeugt, beispielsweise um vorhandene Anwendungen ohne großen Änderungsaufwand auf die anpassbare Oberfläche umzustellen, können wie gewohnt in der Methode init() erzeugt werden. Auch diese Felder können auf der Oberfläche grundsätzlich verschoben werden.
Hinweis:
Bei einer Anwendung, die aus Unteranwendungen besteht, müssen die Objektsichten für die entsprechende Unteranwendung registriert werden. Beispiele finden Sie in den Anwendungen „Artikel“ und „Partner“.
Hinweis:
Anwendungen, in denen Attribute aus 1:n-Beziehungen auch im Designmodus verfügbar sein sollen, müssen einen eigenen DataViewUI für die Objektsicht der Beziehung verwenden und die richtigen anpassbaren Container registrieren. Beispiele hierfür sind Beleg-Anwendungen. (Dies gilt nicht für Erweiterungen der Anwendung.)
Für das automatische Datamapping von der Oberfläche auf das Business Entity (dataToUI bzw. dataFromUI) ist eine Unterstützung in der Anwendung nötig, die im Folgenden beschrieben ist.
Hinweis:
In der SingleObjectMaintenance ist die Unterstützung des Datenmappings bereits vorhanden.
Um das automatische Datamapping in einer Anwendung zu implementieren, ist die im Folgenden beschriebene Programmierung nötig. Mithilfe des hier als anonyme innere Klasse implementierten DataManagers löst die anpassbare Oberfläche das Datamapping aus. Die Aufrufe gehen zunächst in die Anwendung, die wiederum das eigentliche automatische Datamapping am DataViewUI aufruft. In den Methoden dataFromUi und dataToUi hat die Anwendung auch die Möglichkeit, eigene Felder zu mappen. Wenn die Anwendung selbst das Mapping auslösen muss, ruft sie dazu die genannten Methoden selbst auf.
public class XMaintenance extends CisUiApplication {
public void init() {
…
// Data mapping support:
DataViewUI.registerDataManager(this, new DataViewUI.DataManager(){
public void dataFromUI() {
XMaintenance.this.dataFromUi();
}
public void dataToUI() {
XMaintenance.this.dataToUi(); }
});
// DataViewUI:
dataViewUI = (DataViewUI<DataView<T>>) DataViewUI.create(
this, XView.class);
dataViewUI.register(getIdentPane());
dataViewUI.register(getWorkPane());
…
}
void dataFromUi() {
…
dataViewUI.dataFromUi(dataFullAccess);
…
}
void dataToUi() {
…
dataViewUI.dataToUi(dataView);
…
}
6.3 Attributvorrat
Der Attributvorrat der anpassbaren Oberfläche ergibt sich aus der angegebenen Objektsicht, und wird bei aktiviertem Designmodus unter dem Karteireiter „Attribute“ angezeigt. Diese Attribute können einer anpassbaren Oberfläche hinzugefügt werden. Der Attributvorrat enthält:
- alle nicht ausgeblendeten Attribute der Objektsicht (inkl. der Erweiterungen),
- Attribute aus Objektsichten, die über 1:1-Beziehungen erreichbar sind.
Im Attributvorrat sind standardmäßig nur Attribute sichtbar, die aus App-Entwicklungssystemen stammen. Attribute, die nicht aus Apps stammen, sind standardmäßig nicht im Attributvorrat enthalten und müssen deshalb bei Bedarf zum Attributvorrat hinzugefügt werden.
Für Apps gilt zusätzlich, dass die App lizenziert sein muss, falls im Entwicklungsobjekt „App“ ein Lizenzschlüssel eingetragen ist. Dies gilt auch bei der Entwicklung der App auf dem App-Entwicklungssystem.
Hinweis:
Beachten Sie insbesondere auf Adaptierungssystemen, dass Sie den Attributvorrat explizit sichtbar schalten müssen. Weitere Informationen finden Sie in dem Abschnitt „Attributvorrat in Erweiterungen ändern“.
Die Art des automatisch erzeugten Feldes wird automatisch bestimmt oder kann in der Data-Description als EditorFactory (Feld „Editor“ im Entwicklungsobjekt) festgelegt werden. In einigen Fällen wird kein Feld automatisch bestimmt, sondern es muss eine EditorFactory bereitgestellt werden. Näheres ist im Abschnitt 6.7 beschrieben.
Mit dem folgenden Tool-Shell-Befehl können Sie insbesondere bei Fremdschlüsselbeziehungen leichter herausfinden, weshalb ein Feld nicht oder nur-lesbar angezeigt wird:
dbgcls –class:com.cisag.pgm.gui.EditorFactory
Attributvorrat in Erweiterungen ändern
Um in anderen Entwicklungssystemen die Felder nicht zu programmieren, sondern sie durch die anpassbare Oberfläche erzeugen zu lassen, muss einer der folgenden Hooks implementiert werden:
- Hook-Contract-Definition cisag.pgm.appserver.Server,
Hook com.cisag.pgm.appserver.hook.DataViewRegistryHook,
Mit diesem Hook entscheiden Sie, ob in diesem System hinzugefügte neue Attribute im Designmodus zur Verfügung stehen sollen.
Mithilfe der Methode setExtensionCustomizable() der DataViewRegistry können Sie entscheiden, ob Extension- oder Objektsicht-Erweiterungs-Attribute im Entwicklungspräfix der Hook-Implementierung im Designmodus angeboten werden sollen.
- Hook-Contract-Definition cisag.pgm.base.CisUiApplication,
Hook com.cisag.pgm.gui.hook.DataViewUIHook
Setzen Sie am übergebenen CisUiApplicationDataViewUI-Objekt, ob alle oder bestimmte Attribute im Designmodus angeboten werden sollen. Für eine Hook-Implementierung werden zusätzlich eine oder mehrere Anwendungen und eine Objektsicht innerhalb der Anwendungen angegeben, für die die Implementierung gilt.
Hinweis:
Mit den Hooks können Sie nur Attribute beeinflussen, die aus demselben Modul stammen wie die Hook-Implementierung.
Attributvorrat in der Anwendung ändern
Sie können Attribute aus einer Objektsicht in einer Anwendung explizit ein- bzw. ausblenden. Sie können am DataViewUI-Objekt einstellen, welche Attribute im Designmodus angeboten werden:
DataViewUI#setAttributesVisible()
DataViewUI#setAttributeVisible()
6.4 Reihenfolge im Datemapping
Die Daten werden automatisch zwischen der Objektsicht und den Feldern ausgetauscht, sofern die Felder durch die anpassbare Oberfläche erzeugt wurden. Die Reihenfolge des Datamappings kann für die Anwendung wichtig sein.
Beispiel:
Die Auftragsart muss vor der Auftragsnummer von den Feldern in die Objektsicht übernommen werden, da die Auftragsnummer u.U. nur dann übernommen werden kann, wenn die Art bekannt ist.
Die Reihenfolge des Datamappings kann bei Bedarf beeinflusst werden.
Reihenfolge in der Anwendung ändern
In der Anwendung kann die Reihenfolge des Datamappings mit der Methode DataViewUI#addDependency() geändert werden.
Reihenfolge in Erweiterungen ändern
Für Erweiterungen gibt es in der Hook-Contract-Definition com.cisag.pgm.base.CisUiApplication, Hook com.cisag.pgm.gui.hook.DataViewUIHook die Methode addDependency().
6.5 Feldeigenschaften
Der allgemeine Feldzustand (sichtbar, enabled, editierbar, Pflichtfeld) wird zum einen durch die Angaben in der Objektsicht oder Objektsicht-Erweiterung bestimmt und kann darüber hinaus dynamisch im DataObject oder in der DataExtension verändert werden. Folgende Enum-Konstanten stehen für die dynamische Bestimmung der Feldeigenschaften zur Verfügung:
Enum-Wert | Bedeutung |
UNMODIFIED | Feldzustand wie im XML der Objektsicht oder Objektsicht-Erweiterung angegeben, ansonsten sichtbar, enabled, editierbar. Wird in der Regel für Felder eines fremden Moduls zurückgegeben. |
HIDDEN | Das Feld wird unsichtbar, es sei denn, es ist ein Pflichtfeld. |
DISABLED | Das Feld wird sichtbar, ist aber deaktiviert. |
READ_ONLY | Das Feld wird sichtbar, ist aktiviert, aber nicht editierbar. |
REQUIRED | Das Feld wird sichtbar, ist aktiviert, editierbar und ist ein Pflichtfeld. |
EXCLUDED | Das Feld wird unsichtbar, auch wenn es ein Pflichtfeld ist. |
Es ist auch möglich, Felder zu verändern, die aus einem anderen Modul stammen. Beispielsweise kann ein Feld auf HIDDEN gesetzt werden, um es durch ein eigenes Feld/Attribut zu ersetzen. Falls mehrere Erweiterungen den Zustand desselben Feldes ändern (d.h. nicht UNMODIFIED zurückgeben), werden die Änderungen automatisch zusammengefasst.
6.5.1 DataDescriptionModification für aktuelle Objektsichten
Sie können Feldeigenschaften für die aktuelle Objektsicht mit den Methoden DataObject#getDataDescriptionModification(Enum) bzw.
DataExtension#getDataDescriptionModification(Enum)
im jeweiligen DataObject bzw. DataExtension dynamisch ändern. Das Feld bzw. das Attribut wird durch den Attribut-Enum der Objektsicht identifiziert.
Beim Implementieren der getDataDescriptionModification-Methode muss beachtet werden, dass diese Methode für alle Attribute, auch für Attribute aus fremden Modulen, aufgerufen wird.
Sollen nur bestimmte Felder beeinflusst werden, kann folgendes Muster verwendet werden:
public DataDescriptionModification getDataDescriptionModification(Enum attribute) {
switch (((CountryView.Attribute) attribute)) {
case $ado_countryEuroCurrency:
if (!getView().isEuMember()) {
return DataDescriptionModification.READ_ONLY;
}
break;
}
return super.getDataDescriptionModification(attribute);
}
Um alle Felder des eigenen Moduls zu beeinflussen, aber keine Felder fremder Module, kann über die Methode isAssociated() abgefragt werden, ob ein Attribut aus dem eigenen Modul, d. h. der eigenen App bzw. Adaptierung, stammt.
public DataDescriptionModification getDataDescriptionModification(Enum attribute) {
if ( !isAssociated(attribute)) {
return super.getDataDescriptionModification(attribute);
} else if ( !isEnabled()) {
return DataDescriptionModification.EXCLUDED;
}
if (attribute==Item.Attribute.$xyz && isX()) {
return DataDescriptionModification.READ_ONLY;
} else {
return DataDescriptionModification.UNMODIFIED;
}
}
6.5.2 DataDescriptionModification für entfernte Objektsichten
Wenn Sie beispielsweise alle Felder eines Business Entitys auf nur-lesbar schalten möchten, dann müssen Sie berücksichtigen, dass mit Objektsicht-Erweiterungen über 1:1-Beziehungen neue Objektsichten zum Business Entity hinzugefügt worden sein können. Wenn Sie das Interface DataObject.DataDescriptionModificationProvider mit der Methode getDataDescriptionModification(Path) implementieren, dann können Sie für einen Pfad eine DataDescriptionModification zurückgeben. Damit können Sie für alle durch 1:1-Beziehungen erreichbaren Objekte eine DataDescriptionModification angeben.
Bei der Implementierung der Methode getDataDescriptionModification(Path) müssen Sie analog zu der Methode getDataDescriptionModification(Enum) beachten, dass Sie die Eigenschaften fremder Attribute beeinflussen können.
Beachten Sie, dass Pfade nicht unbedingt eindeutig sind. Mehrere unterschiedliche Pfade können ausgehend von der gleichen Objektsicht zum gleichen Ziel führen. Vergleichen Sie daher möglichst nur die relevanten Teile eines Pfades, aber nicht den vollständigen Pfad. Der Pfad bietet hierfür die Methoden startsWith, endsWith und contains an.
public DataDescriptionModification getDataDescriptionModification(Path path) {
if ((! isMyAddressEnabled()) &&
path.contains(Relations.$MyAddress)) {
return DataDescriptionModification.DISABLED;
}
return DataDescriptionModification.UNMODIFIED;
}
6.6 Meldungszuordnung
In der anpassbaren Oberfläche können Meldungen den Feldern über den DataView-Pfad zugeordnet werden. Diese Möglichkeit besteht für jedes Feld, das nicht durch die Anwendung, sondern durch die anpassbare Oberfläche in die Anwendung eingefügt wurde. Der DataView-Pfad ersetzt dabei die ProgramMessageID für herkömmliche Felder.
Die Zuordnung erfolgt vor dem Senden einer Meldung mit einer der folgenden Methoden. Attribute und Beziehungen werden dabei anhand der Enums im erzeugten View angegeben:
CisMessageManager#setProgramMessageDataViewPath(ElementEnum…)
CisMessageManager#setProgramMessageDataViewPaths(Path…)
Die zweite Methodensignatur erlaubt, Meldungen mehreren Feldern gleichzeitig (mehrere Pfade) zuzuordnen. Die Pfade für die zweite Methodensignatur können an der Klasse com.cisag.pgm.base.Path unter anderem mit der folgenden Methode abfragt werden:
Path getInstance(Enum<?>… attributeOrRelation)
Ein Beispiel finden Sie in der Hook-Implementierung in Abschnitt 5.1.
Um die Verwendung von DataView-Pfaden auch für Felder, die durch die Anwendung erzeugt wurden, zu ermöglichen, können die Pfade direkt an Feldern gesetzt werden. Hierzu wird in der Anwendung die Methode
VisualElement#setDataViewPath(Path dataViewPath)
verwendet.
6.7 EditorFactory und AttributeContext
Eine EditorFactory ist eine Java-Klasse, die in der DataDescription eines Objektsicht-Attributs hinterlegt werden kann, um ein eigenes Feld für das Attribut zu implementieren.
Felder für primitive Datentypen, Special Parts, und Entity-Felder mit einteiligem Business Key werden von der anpassbaren Oberfläche automatisch erzeugt. In anderen Fällen muss eine EditorFactory implementiert werden. Sie können existierende Felder einfach in einer EditorFactory verwenden.
Das folgende Beispiel zeigt eine EditorFactory für eine Partner-GUID, und kann in entsprechenden DataDescriptions eingetragen werden.
public class PartnerEditorFactory implements EditorFactory {
public Editor<byte[]> createEditor(byte[] guid,
DataDescription dataDescription, AttributeContext context) {
return new PartnerEditor(guid, dataDescription, context);
}
protected static class PartnerEditor implements Editor<byte[]> {
private final PartnerField field;
private final DataDescription dataDescription;
protected PartnerEditor(byte[] guid,
DataDescription dataDescription, AttributeContext context) {
this.dataDescription = dataDescription;
field = new PartnerField(Guid.toHexString(guid),
(String) dataDescription.getValue(DataDescription.PATH),
true);
}
public VisualElement getVisualElement() {
return field;
}
public void initVisualElement() { }
@Override
public void setValue(byte[] value,
DataDescriptionModification properties)
{
field.updateProperties(properties, dataDescription);
field.setGuid(value);
}
@Override
public byte[] getValue() {
return field.getGuid();
}
}
}
Das Datamapping erfolgt über die Methoden setValue und getValue. Diese Methoden erhalten bzw. liefern in diesem Beispiel die Partner-GUID.
Der dritte Parameter der Methode createEditor ist der AttributeContext und wird in diesem Beispiel nicht verwendet. Der AttributContext enthält mindestens unter dem Schlüssel DataView.class die Objektsicht des Business Objects, in dem das Attribut enthalten ist. Damit kann ein von der EditorFactory erzeugter Editor außer auf die Partner-GUID auch auf andere Attribute lesend zugreifen. Je nach Anwendung können im AttributeContext auch noch weitere Informationen enthalten sein.
6.8 Komplexe GUI-Komponenten
In der anpassbaren Oberfläche können auch GUI-Komponenten zur Verfügung gestellt werden. GUI-Komponenten können Views mit mehreren Feldern oder auch eine Tabelle oder Liste sein. Im Designmodus wird die GUI-Komponente als Ganzes auf der Oberfläche der Anwendung platziert und kann als Ganzes verschoben werden.
GUI-Komponente (umrahmter Bereich) in der anpassbaren Oberfläche.
Das im Folgenden gezeigte Beispiel realisiert eine GUI-Komponente mit einer 1:n-Beziehung auf ein Business Object mit Visualisierung als Tabelle. Die GUI-Komponente wird in eine Anwendung auf Basis von SingleObjectEntity eingefügt. Die Beschreibung bezieht sich auf die Erstellung von GUI-Komponenten als Erweiterung in einer Anwendung.
In der Objektsicht-Erweiterung wird die GUI-Komponente durch ein virtuelles Attribut repräsentiert, wie im folgenden Beispiel gezeigt. Der logische Datentyp (XML: „datatype“) des virtuellen Attributs spielt keine Rolle und kann beispielsweise auf dem primitiven Datentyp boolean basieren.
<virtualattribute property=”MUTABLE”>
<name>ado_simple_multipleDependent</name>
<datatype>com.ado.ext.app.simple.common.MultipleDependentEditorFactory
</datatype>
</virtualattribute>
Im DataObject bzw. DataExtension müssen Zugriffsmethoden für das virtuelle Attribut pro forma implementiert werden. Die GUI-Komponenten erhalten ihre Daten nicht durch diese Zugriffsmethoden, sondern durch die Objektsicht, die im AttriubteContext in der GUI-Komponente zur Verfügung steht.
Die Datenhaltung erfolgt mithilfe der PGM-Klasse CisObjectContainer, das erfolgt über Implementierungen von Business-Entity-Hooks. Ein Objekt der Klasse CisObjectContainer wird in einem Zustandshook gehalten. Zusätzlich müssen folgende Logikhooks für das Öffnen, Speichern, etc. der 1:n-Beziehung implementiert werden:
- SingleObjectDependentHook#init()
- SingleObjectApplyDefaultsHook#applyDefaults()
- SingleObjectDependentHook#load()
- SingleObjectDependentHook#duplicate()
- SingleObjectValidateUpdateHook#validateUpdate()
- SingleObjectDependentHook#update()
- SingleObjectDependentHook#delete()
- SingleObjectDependentHook#makeUnchanged()
- SingleObjectDependentHook#isChanged()
Für die GUI-Komponente muss die PGM-Klasse ContainerTableEditor abgeleitet werden. Diese GUI-Komponente ist ein Editor, der über eine EditorFactory in der DataDescripton des Objektsicht-Attributs com.ado.ext.app.simple.common.MultipleDependentEditorFactory registriert wird. Folgender Codeausschnitt zeigt den Zugriff der GUI-Komponente auf ihre Daten (im Zustandshook gehaltener CisObjectContainer).
DeliverySlipTypeView dataView = (DeliverySlipTypeView) context.getValue(
DataView.class);
SimpleState state = (SimpleState) dataView.getHookState();
CisObjectContainer c = state.getMultipleDependentContainer();
Der AttributeContext (Variable context) wird über die EditorFactory übergeben.
Hinweis für Editoren mit eigenen Actions:
Durch das Auslösen von Actions innerhalb eines Editors werden auch automatisch die Methoden „DataManager#dataFromUi()“ und „DataManager#dataToUi()“ aufgerufen. Durch Kennzeichnung des Editors mit der Annotation „com.cisag.pgm.gui.annotation.DataManagerActions“ kann dieses Standardverhalten angepasst werden.
[1] Das ist immer möglich, es sei denn, Signaturen von Hook-Methoden überschneiden sich.