Anpassung durch Python-Skripte
Sciformation ELN kann an vielen Stellen durch Python-Skripte erweitert oder an besondere Anforderungen angepaßt werden:
- für Aufgaben bei Start oder Herunterfahren von Sciformation ELN,
- bei der Ausleihe oder Rückgabe von Chemikalien (z.B. zur Etablierung spezieller Sicherheitsrichtlinien wie Ausleihdauer oder Benachrichtigungen),
- beim Verkauf von Lagerchemikalien (zur Gebindeauswahl und Preisberechnung),
- zur Durchführung regelmäßiger Berichts-, Kontroll- oder Wartungsfunktionen,
- zur Verarbeitung von Einmaltokens, z.B. für Freigabeerteilungen per Email,
- zur das Hinzufügen durch Knöpfe aufrufbarer Funktionalität in Ergebnislisten,
- zur Aufbereitung von Ergebnislisten zum Export,
- zur Nachbearbeitung konvertierter Analytikdaten (z.B. zur zusätzlichen Erstellung langzeitarchivfähiger Dateiformate) oder
- zur Validierung von Datensätzen vor der Ablage im Archivsystem.
In der Konfigurationsdatei kann mit dem Parameter py_folder_customization ein Speicherort für die betr. Skripte angegeben werden, sowohl als relativer Pfad wie "/WEB-INF/clientSpecific/.../scripts/customization" als auch absolut wie "/home/sciformation/customization". Dort kann zum einen ein allgemeines Skript customization.py abgelegt werden, zum anderen spezielle Skripte für weiterführende Aufgaben.
Start oder Herunterfahren von Sciformation ELN
Beim Start von Sciformation ELN auf dem Server (nicht dem Login) wird im allgemeinen Skript customization.py (im durch den Parameter py_folder_customization gesetzten Skriptordner) die Funktion customizeDeploy() aufgerufen, analog dazu wird beim Herunterfahren customizeUndeploy() aufgerufen. Diese Skripte können z.B. genutzt werden, um nach dem Start noch nötige Hilfsdateien zu kopieren oder den Status zu protokollieren.
Ausleihe/Rückgabe von Chemikalien
Vor der Ausleihe eines Chemikaliengebindes wird im Skript customization.py die Funktion customizeBorrow() aufgerufen, wobei der Ausleiheeintrag als Variable cdbContainerLoan verfügbar ist. Das Skript kann den Ausleiheeintrag prüfen, ggf. verändern und - falls nötig - eine Zeichenkette mit einer Fehlermeldung zurückgeben, um die Ausleihe zu verweigern. Analog dazu wird beim Versuch der Rückgabe customizeReturn() aufgerufen.
Verkauf von Lagerchemikalien
Anders als beim Direktkauf von Chemikalien ist beim Verkauf von Lagerchemikalien häufig gewünscht, daß die zu nutzenden bzw. anzubrechenden Gebinde nach bestimmten Kriterien ausgewählt werden, sofern die Auswahl nicht explizit durch Angabe einer Chargennummer oder eines Gebindebarcodes erfolgt. Hierzu wird - sofern vorhanden - durch webclient.list.WhsChemicalPurchaseItemRenderer das Skript "whs_chemical_purchase_selection.py" aufgerufen mit folgenden Variablen:
- den Steuerelementen
- searchbox: der von Anwender genutzten Combobox, ggf. null,
- feedbackLabel: einem Label zur Anzeige von Hinweisen, ggf. null,
- totalPriceBox: einer GrossNetBox, die mit dem zu zahlenden Preis gekoppelt ist, ggf. null,
- whsChemicalPurchaseItem: dem entity.WhsChemicalPurchaseItem der betreffenden Zeile,
- searchText: dem eingegebenen Suchtext,
- selectedEntity: dem Wert des aktuell ausgewählten Comboitems, ggf. null,
- whsChemicalPurchaseItemRenderer: dem aktiven WhsChemicalPurchaseItemRenderer,
- rowBinder: dem DataBinder der betreffenden Zeile,
- srcEvent: dem auslösenden Event vom Typ "onChanging" bzw. "onSelect",
- currentSession: der aktiven HttpSession,
Typischerweise wird das Skript basierend auf searchText Alternativen zur Auswahl anbieten oder direkt eine solche auswählen. Geänderte Daten können durch rowBinder.loadAll() in der Oberfläche aktualisiert werden, alternativ/ergänzend können dem Nutzer über feedbackLabel Hinweise angezeigt werden.
Im Anschluß an die Auswahl eines Angebots oder Gebindes sowie nach Eingabe einer geänderten Menge wird zur Preisermittlung das Skript "whs_chemical_purchase_price.py" aufgerufen, sofern es vorhanden ist. Das Skript muß auf Basis der gewählten Menge einen durch den Abnehmer zu zahlenden Netto-Endpreis ermitteln. Die verfügbaren Variablen sind identisch, nur searchText und selectedEntity werden nicht belegt.
Generell könnte es möglich sein, für die Aufgaben "Gebindeauswahl" und "Preisberechnung" ein einzelnes Skript zu nutzen, eine Trennung erscheint aber sinnvoll.
Regelmäßige Aufgaben
Zur Durchführung regelmäßiger Berichts-, Kontroll- oder Wartungsfunktionen können im betr. Skriptordner Python-Skripte mit den Namen
- minutely.py (minütliche Ausführung)
- hourly.py (Ausführung zu jeder vollen Stunde, oder zur Minute, die für timer_hourly_minute in der Konfigurationsdatei angegeben ist)
- daily.py (tägliche Ausführung um 4:00 oder zur Stunde timer_daily_hour in der Konfigurationsdatei)
- monthly.py (Ausführung am Monatsersten um 1:00, oder am Tag timer_monthly_day zur Stunde timer_monthly_hour, wobei Tage < 1 vom Monatsende zurückgezählt werden)
Dabei wird die Funktion cronRun() aufgerufen mit folgenden Variablen:
- em verweist auf einen EntityManager mit einer offenen Transaktion utx,
- now (Date) auf das aktuelle Datum,
- jobName auf den Namen des laufenden Skripts,
- lastRun ggf. auf den Protokolleintrag des letzten Durchlaufs, lastSuccessfulRun auf den letzten erfolgreichen Durchlauf
Einmaltokens
Einmaltoken können genutzt werden, um Personen das einmalige Anstoßen von Prozessen in Sciformation ELN zu erlauben, ohne daß ein vorheriger Login notig ist. Beim Anlegen eines Einmaltokens (nur programmatisch erzeugbar) kann der Dateiname eines Python-Skripts (triggerScript, im betr. Skriptordner) sowie ein Funktionsaufruf (triggerFunction) angegeben werden. Es werden folgende Variablen übergeben:
- sysTrigger (SysTrigger, der auslösende Einmaltoken),
- orgPerson (OrgPerson, für den zugeordneten Benutzer, kann null sein),
- now (Date) für das aktuelle Datum,
- em (EntityManager), keine offene Transaktion sowie
- errors (List<String>) als Möglichkeit, dem Fehler anzuzeigen.
Hinzufügen durch Knöpfe aufrufbarer Funktionalität in Ergebnislisten
Mitunter kann der Wunsch bestehen, für Einträge in einer Ergebnisliste zusätzliche Funktionalität bereitzustellen, z.B. die Erstellung personenbezogener CMR-Reports nach Bedarf. Dazu kann zunächst eine kommagetrennte Liste von Bezeichnern verschiedener Knöpfe (=Funktionen) über den Parameter custom_list_buttons_XyzEntity gesetzt werden, z.B. cmrReport - der Name "br" in der Liste erzeugt einen Zeilenumbruch. Für die jeweiligen Knöpfe legen folgende Parameter Aussehen und Funktionalität fest:
- button.cmrReport.pyScript: Dateiname des Python-Skripts
- button.cmrReport.icon: Dateiname des Symbols
- button.cmrReport.langKey: interner Schlüssel für den lokalisierten Text
- button.cmrReport.sortKey: Eigenschaft, die zur Sortierung genutzt werden soll
- button.cmrReport.title: statischer Tooltip-Text
Das Skript erhält beim Anklicken der Schaltfläche folgende Variablen:
- viewInstance: die Instanz der webclient.zkgrid.renderer.GenericView-Tochterklasse, erlaubt auch Zugriff auf die Controller
- param: URL-Parameter als Map
- requestScope: vgl. ZK-Dokumentation
- buttonForEntityType: Bezeichner des Knopfes, z.B. cmrReport
- entity: Objekt der betreffenden Zeile
- event: Klick-Event
Aufbereitung von Ergebnislisten zum Export
Beim Export von Ergebnislisten kann es wünschenswert sein, Spalten zu ergänzen, zu verändern oder auszufiltern, ebenso kann gewünscht sein, die exportierbare Datenmenge - z.B. aus Geheimhaltungsgründen - zu beschränken. Zu diesem Zweck kann man via "System > Berichte & Export" Exportanpassungen einrichten. Dabei kann man Python-Skripte aus dem Skriptverzeichnis "customization" angeben, die vor dem Datenexport aktiv werden sollen. Im "Skript zur Datenanpassung" wird die Funktion customizeData() aufgerufen mit
- der vorgefilterten Liste filteredList (List),
- den Optionen options (Map),
- dem aktiven Exportmodus exportMode (int)
- EXPORT_PRINT = 1: Druckausgabe
- EXPORT_LABELS = 2: Etikettendruck
- EXPORT_PDF = 3: Berichtserstellung
- EXPORT_LIST = 4: Listenausgabe im Browser
- EXPORT_INTERFACE = 5: Zugriff auf Datenschnittstelle
- die aktive Exportanpassung sysExportCustomizer (SysExportCustomizer) sowie
- log (List<String>) als Möglichkeit, dem Nutzer Warnungen oder Fehler anzuzeigen
Analog zur Anpassung von Ergebnislisten im Browser können auch für den Export Listenspalten hinzugefügt, entfernt oder umsortiert werden. Dabei wird im für "Skript zur Ausgabeanpassung" angegebenen Skript die Funktion customizeColumns() aufgerufen, mit folgenden Variablen:
- colMap (vom Typ Map<String, EnhancedColumn>, interne Namen verweisen auf Spaltendefinitionen),
- columnVisible (Set<String>, interne Namen sichtbarer Spalten) und
- columnOrder (List<String>, Reihenfolge der Spalten, repräsentiert durch deren interne Namen)
- exporter (IFGridExporter, Exportmodul wie webclient.zkgrid.exporter.XlsExporter)
Mit diesen Mitteln können maßgeschneiderte Datenexporte aus Sciformation ELN heraus durchgeführt werden. In der Konfigurationsdatei kann durch die Angabe von export_max_size (in Bytes) die maximale Dateigröße für Datenexporte begrenzt werden.
Nachbearbeitung konvertierter Analytikdaten
Die speziellen Python-Datenkonverter versuchen, aus bereitgestellten Rohdaten Vorschaugrafiken zu generieren sowie Signalmuster oder Volltexte zu extrahieren, die dann in der Datenbank oder im Archiv abgelegt werden. Das zurückgegebene Objekt vom Typ analytics.IFAnalyticalData bietet über getImages() Zugriff auf eine Liste von analytics.AnaDataImageContainern, die ihrerseits über die Methoden getImage() bzw. getImageHigh() Zugriff auf java.awt.image.BufferedImages erlauben. Möchte man nun diese Bilder im langzeitarchivfähigen TIFF-Format speichern oder z.B. mit einem Wasserzeichen versehen, dann kann dies über ein Skript rawDataPostProc.py im Skriptordner (definiert durch den Parameter py_folder_customization) erfolgen. Im Skript wird die Funktion postProc() aufgerufen mit folgenden Variablen:
- rawData (analytics.MemFS, Zugriff auf die bereitgestellten Rohdaten)
- entity (zugeordnetes Datenbankobjekt),
- procResult (analytics.IFAnalyticalData, Arbeitsergebnis des Datenkonverters),
Validierung von Datensätzen vor der Ablage im Archivsystem
Vor der Übertragung von Daten ins Langzeitarchiv kann es sinnvoll sein, eine erweiterte Validierung durchzuführen und dadurch sicherzustellen, daß nur vollständige Datensätze archiviert werden. Dies über ein Skript archivalValidation.py im Skriptordner (definiert durch den Parameter py_folder_customization) erfolgen. Im Skript wird die Funktion archivalValidation() aufgerufen mit folgenden Variablen:
- mainObject (zugeordnetes Datenbankobjekt),
- fileWrapper Listen von Objekten des Typs archive.filewrapper.FileWrapper, die Zugriff auf die zu archivierenden Rohdaten (z.B. als byte[],) und ein zugehöriges Objekt zur Generierung des Dateipfads und -namens (mit Hilfe des PathGenerators) geben
- emSave (EntityManager mit einer offenen Transaktion),
- sessionId (zu verwendende ID des aktiven Websitzung),
- forUserName (Benutzername des aktiven Benutzers) sowie
- errors (List<String>) als Möglichkeit, dem Fehler anzuzeigen.
Customization using Python scripts
Sciformation ELN can be customized in various ways with the help of Python scripts:
- for tasks to run after deployment or shutdown of Sciformation ELN,
- when borrowing or returning chemicals (e.g. to enforce special safety regulations or notifications),
- when selling chemicals from stock (for container selection and pricing),
- to regularly execute reporting, monitoring or maintenance functionality,
- to process one-time tokens, e.g. to trigger ordering processes by email,
- for adding button-triggerable functionality to result lists,
- for customizing result lists before the can be exported,
- to post-process converted analytical data ( e.g. to provide long-term archivable image data) or
- to validate data sets prior to archival.
In the configuration file, administrators can define a parameter py_folder_customization pointing to folder for customization scripts, either as relative path like "/WEB-INF/clientSpecific/.../scripts/customization" or as absolute one like "/home/sciformation/customization". A general script customization.py within this folder serves for simple tasks, while specific ones can be used for more complex operations.
Deployment or shutdown of Sciformation ELN
Upon deployment of Sciformation ELN on the server (not when logging in), the function customizeEnploy() within the general script customization.py (in the scripting folder as defined by py_folder_customization) is called. In the same way, the function customizeUnenploy() is called at undeployment. These scripts can help setting up any folder structures, or for logging purposes.
Borrowing or returning chemicals
Prior to borrowing a chemical, the function customizeBorrow() within customization.py is called, with the variable cdbContainerLoan representing the loan entry. The script can validate or modify the entry, or - if required - return an error message to forbid the borrowing. In the same way, when returning a chemical, customizeReturn() is called.
Selling chemicals from stock
When selling chemicals from stock, in many cases, the container to use or open shall be determined upon custom rules, unless the clerk explicitly selects a container to use, e.g. by entering a lot No. or a container barcode. For this selection task, the webclient.list.WhsChemicalPurchaseItemRenderer will call the sript "whs_chemical_purchase_selection.py" (if present) with the following variables:
- the controls
- searchbox: the Combobox used, may be null,
- feedbackLabel: a Label to give feedback, may be null,
- totalPriceBox: a GrossNetBox linked to the total net price, may be null,
- whsChemicalPurchaseItem: the entity.WhsChemicalPurchaseItem of the respective row,
- searchText: the search text entered,
- selectedEntity: the value of the currently selected Comboitem, may be null,
- whsChemicalPurchaseItemRenderer: the currently active WhsChemicalPurchaseItemRenderer,
- rowBinder: the DataBinder of the respective row,
- srcEvent: event triggered Event, of type "onChanging" or "onSelect",
- currentSession: the currently active HttpSession,
Typically, the script will offer alternatives to the user for selection, based on searchText, or directly select one. Changed data can be loaded into the user interface by calling rowBinder.loadAll(), alternatively or in addition, feedback can be displayed using feedbackLabel.
After selecting a container or pricing offer, and after any change to the amount sold, the script "whs_chemical_purchase_price.py" will be called to determine the price, if present. The script has to calculate the total net price to pay by the client. All variables present are identical to the above, except searchText and selectedEntity are missing.
In general, it might be possible to use only one script for "source container selection"and "pricing", but splitting these tasks seems advisable:
Regular tasks
To regularly perform reporting, monitoring or maintenance tasks, Python scripts in the scripting folder will be called regularly
- minutely.py (every minute)
- hourly.py (every clock hour, or at the minute defined by timer_hourly_minute in the configuration file)
- daily.py (daily at 4:00am or at the hour defined by timer_daily_hour in the configuration file)
- monthly.py (monthly at the first at 1:00am, or on the day defined by timer_monthly_day and the hour given by timer_monthly_hour, while days < 1 will be counted from the end of the month)
In every case, the function cronRun() will be called with the following set of variables:
- em refers to an EntityManager with an open transaction utx,
- now (Date) contains the current date,
- jobName the name of the currently running job,
- lastRun may refer to an entry describing the last run, lastSuccessfulRun on the last successful run
One-time tokens
With a one-time token, users can trigger processes within Sciformation ELN only once, without being logged in. When creating a one-time token (only programmatically), the file name of a Python script (triggerScript, in the resp. script folder) and a function name (triggerFunction) can be defined. The following variables are avilable to the script:
- sysTrigger (SysTrigger, the one-time token triggered),
- orgPerson (OrgPerson, the assigned user, can be null),
- now (Date) the current date,
- em (EntityManager), no open transaction and
- errors (List<String>) extensible list of encountered problems.
Adding button-triggerable functionality to result lists
In some situations, it may be useful to offer additional functionality for entries within result lists, e.g. to generate personal CMR reports when required. Set the parameter custom_list_buttons_XyzEntity to a comma-separated list of identifiers for the different buttons (=functionality), e.g. cmrReport - if the identifier "br" is found in the list, a line break is created. For the respective buttons, the following parameter define appearance and functionality:
- button.cmrReport.pyScript: file name of the Python script
- button.cmrReport.icon: file name of the icon
- button.cmrReport.langKey: internal key of the localized text
- button.cmrReport.sortKey: property to use for sorting
- button.cmrReport.title: static tooltip text
When the button is clicked, the following variables are passed to the script:
- viewInstance: the active instance of the respective webclient.zkgrid.renderer.GenericView child class, also gives access to the controller
- param: URL parameters as Map
- requestScope: see ZK documentation
- buttonForEntityType: identifier of the button, e.g. cmrReport
- entity: object of the respective line
- event: click event
Data export customization
When exporting result lists, it may be required to add, modify or remove columns, or to limit the number of data sets a user can export, e.g. to prevent excessive use. For this purpose, administrators can create "export customizers"via "System > Reports & exporting". There, it is possible to choose scripts from the scripting folder "customization" which should be activated prior to an export operation. In the "Data customization script", the function customizeData() is called with
- the pre-filtered list filteredList (List),
- any options (Map),
- the currently active export mode exportMode (int)
- EXPORT_PRINT = 1: printing
- EXPORT_LABELS = 2: label printing
- EXPORT_PDF = 3: report creation
- EXPORT_LIST = 4: list output in browser
- EXPORT_INTERFACE = 5: access through the data interface
- the currently active export customizer sysExportCustomizer (SysExportCustomizer) and
- log (List<String>) as a way to notify the user about warnings or errors
The data columns exported can be custmoized in the same way like list views displayed in the browser, with columns added, removed or rearranged. For this, the function customizeColumns() of the "Output customization script" is called with the following variables:
- colMap (of type Map<String, EnhancedColumn>, internal names reference column definitions),
- columnVisible (Set<String>, internal names of visible columns) and
- columnOrder (List<String>, left-to-right order of internal column names)
- exporter (IFGridExporter, export module, like webclient.zkgrid.exporter.XlsExporter)
With these means, you can create tailored data exports for the data stored within Sciformation ELN. The maximum file size for data exports can be limited by setting the parameter export_max_size (in bytes) in the configuration file.
Post-processing of analytical data
The specialized Python data converters attempt to generate preview images, extract signal patterns or full texts out of raw analytical data, which can be stored in the databse or the archive system. They return objects of type analytics.IFAnalyticalData, whose method getImages() gives access to a list of analytics.AnaDataImageContainern, providing access to java.awt.image.BufferedImages through the methods getImage() or getImageHigh(). To store these images in file formats suitable for long-term archiving or to embed a watermark, the script rawDataPostProc.py in the script folder (as defined by py_folder_customization) can be used. In the script, the function postProc() is called with the following variables:
- rawData (analytics.MemFS, access to the raw data provided)
- entity (assigned database object),
- procResult (analytics.IFAnalyticalData, output of the data converter),
Validation prior to archival
Prior to transmission of data into long-term archiving systems, it can be useful to perform an extended validation, to ensure that only complete datasets are stored. This procedure can be implemented using a script archivalValidation.py in the script folder (as defined by py_folder_customization). The function archivalValidation() will be called with the following variables:
- mainObject (assigned database object),
- fileWrapper list of archive.filewrapper.FileWrapper objects giving access to the raw data to be archived (e.g. as byte[],) and a related object to generate the path and filename from (using a PathGenerator)
- emSave (EntityManager with an open transaction),
- sessionId (the ID of the currently active web sessions),
- forUserName (username of the currently active user) and
- errors (List<String>) as a way to indicate errors.