Teilnehmer

web.sta – web basierte Appli­kation, Ziel-Webbrowser ist Internet Explorer der Version 9 und 11

TextSystem – eine eigen­ständige Desktop-Anwendung, basierend auf Java/Swing

Inter­me­dia­teLayer – eine Client-Server Anwendung, die web.sta und TextSystem mitein­ander verbindet.

web.sta kann TextSystem über den Inter­me­dia­teLayer starten. Inter­me­dia­teLayer erstellt zu diesem Zweck einen HTTP-Server und web.sta sendet einfache GET- oder POST-Abfragen an den localhost. Inter­me­dia­teLayer verar­beitet die Eingangs­pa­ra­meter und startet das TextSystem. Da keine Rückmeldung erfor­derlich ist, ist das Inter­ak­ti­ons­schema einfach und robust genug.

Citrix

In einer Citrix-Umgebung ist es nicht möglich, mehrere Listening-Sockets für dieselbe IP-Adresse und denselben Port zu erstellen. Man muss entweder den Port oder die IP-Adresse ändern. Citrix bietet jedoch einen spezi­ellen Mecha­nismus an, um diese Einschränkung zu umgehen, ohne den Algorithmus des Programms zu ändern. Dieser Mecha­nismus wird als „Virtual IP Loopback“ bezeichnet. Hier muss der Adminis­trator einfach die erfor­der­lichen Anwen­dungen im Citrix-Konfi­gu­ra­ti­ons­fenster konfi­gu­rieren. Die Anwendung, die „localhost“ für Socket-Verbin­dungen verwendet, erhält nicht 127.0.0.1, sondern eine IP-Adresse in der Form 127.0.0.<SID + 1>, wobei SID die Sitzungs-ID des Windows-Benutzers ist.

Die Proble­matik

Unter IE9 (und auch mit anderen Browsern) unter Windows Server 2008 R2 funktio­nierte dies alles einwandfrei. Dann jedoch wollte der Kunde etwas Neues und Windows Server 2012 R2 erschien mit IE11. Das ganze System hörte auf zu funktio­nieren. Unabhängig von den Citrix Einstel­lungen versucht IE11 bei Abfragen auf „localhost“ immer eine Verbindung zu 127.0.0.1 herzu­stellen, diese natürlich scheitert, weil auf der Adresse keiner Hörer (Listener) gibt. Nach ein wenig Recherche kamen wir zu dem Schluss, dass dies ein Bug in IE11 sein muss.

RoutingService

Wenn die Virtua­li­sierung des „localhost“ in Citrix-Box für IE11 nicht funktio­niert, schreiben wir sie selbst!
Deshalb entschlossen wir uns, selbst einen Windows-Dienst zu erstellen, der ein einfacher Webserver ist und zu 127.0.0.1 eine Verbindung aufbaut und damit alle Abfragen auf der Grundlage der Sitzungs­nummer des Benutzers an den gewünschten Inter­me­dia­teLayer umleiten. Wir haben keine einfache Lösung gefunden, um die SID zu ermitteln, aber in den Umgebungs­va­riablen haben wir sofort SESSI­ONNAME gefunden. Im Internet Explorer bekommen wir über ActiveX diese Umgebungs­va­riable und übergeben sie als Parameter in der HTTP-Abfrage weiter. Im RoutingService erhalten wir durch den Sitzungs­namen unter wtsapi32.lib die Sitzungs­nummer. Dann leiten wir die HTTP-Abfrage um und senden die Antwort an den IE zurück.

Etwas ist schief gelaufen

Wir haben mit dem Testen und der Integration unseres Service begonnen. Aber nicht alles lief so reibungslos, wie wir es uns gewünscht hatten.
Wie sich heraus­stellte, kann der Name der Sitzung geändert werden, obwohl wir nicht verstanden haben, unter welchen Bedin­gungen dies geschieht. Es kam jedoch häufig vor, dass der Sitzungsname geändert wurde aber IE11 nur den Anfangswert der Umgebungs­va­riablen kennt und diesen Wert dauerhaft an den RoutingService weitergibt.

Was ist in der Registry?

Es war notwendig, einen anderen Weg zu finden, um den Sitzungs­namen zu ermitteln. Wir haben nach Infor­ma­tionen zu Sitzungen in der Registry gesucht und wurden fündig: Unter HKEY_CURRENT_USER \ Volatile Environment ist es möglich eine Liste aller Sitzungen des aktuellen Benutzers abzurufen.

Wenn es nur um eine Anmeldung geht, ist alles in Ordnung, wir können sie lesen und verwenden. Wenn es für einen Benutzer jedoch viele Sitzungen gibt, müssen wir irgendwie feststellen, in welcher Sitzung wir uns befinden. Die beste Möglichkeit die uns einfiel war, den Pfad zum Ordner mit den tempo­rären Dateien abzugleichen.

Beispiel:

Im IE erhalten wir den aktuellen Pfad zu TEMP mithilfe von ActiveX Scripting.FileSystemObject. Auf diese Weise konnten wir den Namen unserer Sitzung ermitteln. Aber das ist nicht alles. Der Wert der Schlüssel in der Volatile Environment ist in der Tat die SID. Somit können wir sofort die erfor­der­liche IP-Adresse in JavaScript abrufen und eine Anfrage an diese senden.

Sollen wir es vereinfachen?

Schließlich können wir die SID abrufen und direkt eine Verbindung herstellen, ohne den RoutingService zu verwenden. Aber der Lösungsweg sieht immer noch nicht schön aus. Die Inter­net­suche hat gezeigt, dass das Problem besteht, aber wie es behoben werden kann wird nirgendwo beschrieben. Und auch Microsoft bietet dazu bisher keine Lösung.

Wir hoffen, dass jemand mit diesem spezi­fi­schen Problem von unserer Erfahrung profi­tieren kann.

In der Software Quality Assurance werden bei der dynami­schen Quali­täts­si­cherung (Software­testen) verschiedene Methoden angewandt, um die Qualität von Produkten und Prozessen abzusi­chern. Anhand einer Dokumen­tation werden die Bestre­bungen Ihrer Qualität testfähig gemacht. Weiter­lesen

Die Imple­men­tierung einer neuen Software­lösung erfordert nicht nur die detail­lierte Auswahl und Anschaffung von Programmen. Die Heraus­for­derung stellt ebenso sehr die strate­gische Einführung der einzelnen Programm­kom­po­nenten, sowie die Sicher­stellung der Kompa­ti­bi­lität zur Erschaffung einer inein­an­der­grei­fenden IT-Infra­struktur dar. Das präzise Zusam­men­spiel techni­scher und organi­sa­to­ri­scher Abhän­gig­keiten und ein sinnvoller Handlungs­ablauf müssen gewähr­leistet werden. Zudem müssen die durch die Änderungen betrof­fenen Prozess­be­tei­ligten in die Imple­men­tierung einge­bunden werden, um die Akzeptanz der neuen Prozesse im Unter­nehmen zu garan­tieren. Nur durch Übung in einem Testumfeld kann die Sicherheit für die spätere Praxis geschaffen werden. Lediglich anwen­der­freund­liche Prozesse führen in der Praxis zum gewünschten Erfolg.

Software Development Lifecycle

Hierzu wird der Prozess des sogenannten Software Development Lifecycle angewendet. Er ist Teil des Quali­täts­ma­nage­ments eines jeden IT-Projekts. Nach Definition der zu erarbei­tenden Ziele, finden Auswahl und Einführung der hierfür notwen­digen Prozess­än­de­rungen sowie IT-Kompo­nenten statt. Daraufhin erfolgt eine Testphase, die das imple­men­tierte System auf Anwen­der­freund­lichkeit, Effek­ti­vität und Effizienz prüft. Durch erprobte Teststra­tegien und Konzepte werden Erkennt­nisse über mögliche Fehler in der Imple­men­tierung aufge­zeigt. Einzel­fall­sze­narien werden in einer Testum­gebung simuliert. Zudem können Änderungs­wünsche zur besseren Bedienung einge­bracht werden. Eine Analyse der Testergeb­nisse führt gegebe­nen­falls zu einer oder mehreren Repeti­ti­ons­phasen, inklusive notwen­diger Fehler­be­he­bungen und Anpas­sungen, bis die verein­barten Projekt­ziele erreicht sind. Zur Messung der Zieler­rei­chungs­quote können vorde­fi­nierte Kennzahlen zum Einsatz kommen, die indivi­duell, je nach Unter­nehmen, festgelegt werden.

Durch das Software Testing im Development Prozess kann kein fehler­freier Betrieb des neuen Prozesses garan­tiert werden, da während der Tests lediglich Einzel­fälle geprüft werden. Aller­dings werden erfah­rungs­gemäß aufkom­mende Fehler nach Einführung der Systeme im Lifebe­trieb erheblich reduziert.

Nicht nur für die fachliche Model­lierung von neuen IT-Prozessen sollte ein oder sollten sogar mehrere profes­sio­nelle Berater hinzu­ge­zogen werden. Durch standar­di­sierte und erprobte Erfah­rungen in der Optimierung und Automa­ti­sierung von IT-Prozessen können externe Dienst­leister ebenso wertvolle Unter­stützung während der einzelnen Entwick­lungs­zyklen der Imple­men­tierung der Prozesse bieten. Gerade beim Testing ist eine detail­lierte Dokumen­tation und Begleitung durch Program­mierer sinnvoll und notwendig, damit die richtigen Schluss­fol­ge­rungen aus den Fehlern gezogen werden können, um diese wiederum effizient lösen zu können.

Einheit­liche und verständlich geschriebene Anwen­der­hand­bücher zur Bedienung neuer Systeme, sowie Schulungen werden außerdem in der Regel durch den Dienst­leister zur Verfügung gestellt und müssen somit nicht vom Unter­nehmen selbst konzi­piert werden.

SEHEN SIE UNSER SERVICE ANGEBOT

In Zeiten der stetigen Digita­li­sierung stehen Unter­nehmen verstärkt vor der Heraus­for­derung, die eigene IT-Infra­struktur nicht nur aufrecht zu erhalten, sondern außerdem bestehende Systeme zu moder­ni­sieren und ihre Poten­ziale durch die Umsetzung von techni­schen Innova­tionen zugunsten ihres Wettbe­werbs­vor­teils zu nutzen. Dabei benötigen sie aufgrund fehlender Eigen­res­sourcen profes­sio­nelle Unter­stützung. Doch welcher IT-Dienst­leister passt zum jewei­ligen Unter­nehmen? Welches Leistungs­port­folio deckt die eigenen Erwar­tungen bestmöglich ab?

Die Auswahl an IT-Dienst­leistern in Deutschland ist groß. Grund­sätzlich unter­scheidet man den Markt in drei Beratergruppen.

  • Die erste Gruppe stellen die sogenannten IT-Service-Dienst­leister dar. Sie konzen­trieren sich auf den Betrieb von Rechen­zentren sowie auf Wartung und Support der Anwen­dungs­um­gebung. Ihr Fokus liegt auf der frühzei­tigen Lokali­sierung von System­stö­rungen, Erarbeitung diesbe­züg­licher Lösungen sowie der Warnung, Vorbe­reitung und Begleitung des Kunden zur notwen­digen Anpassung der Software.
  • Die zweite Art der IT-Dienst­leister legt ihren Schwer­punkt auf die betriebs­spe­zi­fische System­ent­wicklung und –integration. Sie haben sich auf die Entwicklung von Indivi­du­al­software sowie deren Betrieb spezialisiert.
  • Die dritte Gruppe verfügt über ein umfas­sendes, zukunfts­ori­en­tiertes Leistungs­spektrum. Dieses beinhaltet eine Kombi­nation aus Management- und IT-Beratung mit der Orien­tierung an kunden- und projekt­spe­zi­fi­schen Anfor­de­rungen. Dazu gehören zum Beispiel Konzep­tio­nierung, Software­ent­wicklung, Reali­sierung innova­tiver IT-Geschäfts­mo­delle unter Einbezug von Trans­for­ma­ti­ons­ma­nagement, Business Prozess Outsourcing und Business Prozess Management.

Aktuell dominieren die IT-Service-Dienst­leister den deutschen Markt des IT-Consul­tings. Durch die steigende Weiter­ent­wicklung hinsichtlich moderner Techno­logien wächst der IT-Berater-Markt einer­seits an sich stetig. Anderer­seits entwi­ckeln sich die Kunden­an­for­de­rungen auf Basis neuer Geschäfts­mo­delle immer mehr in Richtung digitaler Trans­for­mation. Die Nachfrage nach IT-Beratern, die ihren Schwer­punkt auf den reinen Support fixer IT-Struk­turen in Betrieben gelegt haben, reduziert sich aktuell. Zunehmend werden Dienstleistungen nachge­fragt, die die Geschäfts­pro­zesse an die neuen Bedin­gungen der Wirtschaft anpassen. Die Unter­nehmen benötigen Unter­stützung bei Projekten wie etwa bei Expan­si­ons­vor­haben, Aufbau oder Erwei­te­rungen der Social Media Präsenz, der Einbindung von Cloud­lö­sungen oder Multi-Channel-Platt­formen, mit dem Ziel, den Bedin­gungen der allge­meinen Moder­ni­sierung zu genügen.

Bei der Auswahl der hierfür adäquaten, maßge­schnei­derten Software unter­stützen zukunfts­ori­en­tierte IT-Berater. In enger Zusam­men­arbeit mit dem Unter­nehmen werden Projekt­ziele und Vorge­hens­weisen für den Verän­de­rungs­prozess definiert. Struk­tu­rierte und erprobte Analy­se­schritte ermög­lichen indivi­duell auf das Unter­nehmen angepasste Projektstrategien.

SEHEN SIE UNSER SERVICE ANGEBOT

Die externen Anfor­de­rungen an Unter­nehmen hinsichtlich Service­qua­lität, Flexi­bi­lität sowie Nachhal­tigkeit steigen stetig an. Hinzu kommt der erhöhte Kosten­druck des freien Marktes. Unter­nehmen sind mehr und mehr gezwungen, ihre Prozesse zu optimieren und zu automa­ti­sieren, um wettbe­werbs­fähig zu bleiben. Hierzu ist eine genaue Aufnahme und Analyse der Workflow-Landschaft des Betriebs notwendig. Weiter­lesen

Versio­nierung ist innerhalb eines Dokumen­ten­ma­nage­ment­systems (DMS) kein Fremdwort. Norma­ler­weise bedeutet es, dass Historie der Änderungen von Dokumenten gespei­chert wird. In unserem Artikel wird beschrieben, was zu tun ist, wenn die Dokumente aus den Vorlagen erstellt werden und die Vorlagen selbst fortent­wi­ckelt werden können, ohne dass die Abhän­gig­keiten vom Dokument zur Vorlage aufgelöst worden sind.

Bei größeren Unter­nehmen werden für die Erstellung von Dokumenten diverse komplexe Vorlagen umgesetzt. Z.B. auf XML-Basis, wie bei Gerichten und Staats­an­walt­schaften, oder als dot-Datei von MS Word. Die Vorlagen können vonein­ander abhängen, modula­ri­siert werden, Includs (Collec­tions) haben und vieles mehr. Die Dokumente werden mit dynami­schen Daten gefüllt und können eine interne Sprache haben, z.B. Skript­ele­mente oder Makros. Eine Vorlage wird geladen, ggf. inter­pre­tiert, oder es werden die Skripte gestartet, die eine gewisse Dynamik ins Dokument bringen. Wenn in der Skript­sprache die Bedin­gungs­ele­mente verwendet werden, kann es sein, dass einige Vorlagen erst später gelesen werden können, z.B. bei der nächsten Session oder der nächsten Inter­pre­tierung des Dokumentes. Dadurch kommen neue dynamische Daten aus Vorlagen ins Dokument.

Diesen Ablauf kann man grafisch wie folgt darstellen:

 

Jede XML-Vorlage (oder jeder XML-Baustein) kann noch bedingte Elemente haben und auf weitere XML-Vorlagen verweisen. Das Problem dabei: Wenn man versucht, die Vorlagen zu erweitern, könnten alte gespei­cherte Dokumente nicht mehr ablauf­fähig sein. Es können verschiedene Probleme von „Variable nicht gefunden“ bis „das Modul existiert nicht mehr“ auftreten. Um die aus diesen Vorlagen erstellten Dokumente immer inter­pre­tierbar zu halten und die Abhän­gigkeit von der Vorlage aufzu­lösen, gibt es zurzeit zwei Alternativen:

1. Die Vorlagen sollen so entwi­ckeln werden, dass keine Abhän­gig­keiten zwischen den geladenen Vorlagen im Dokument und erwei­terten oder neu entwi­ckelten Vorlagen, auch in abseh­barer Zeit, entstehen können.

2. Ein Versio­nie­rungs­system für die Vorlagen einführen – Die Alter­native zu Nummer 1 ist einfach, könnte aber bei größeren Projekten nicht zu reali­sieren sein, weil fast bei jeder Erwei­terung der Vorlagen alle anderen immer von jemandem darauf hin überprüft werden müssen, ob keine Abhän­gig­keiten entstehen.

Versio­nie­rungs­system

Die Idee ist nun, jede Vorlage zu versio­nieren. Alle XML-Vorlagen müssen dazu über ein Versi­ons­ver­wal­tungs­ystem (z.B. SVN, VSS) versio­niert werden. Die Nummer der Revision sollte in der Vorlage sichtbar sein, z.B. in Form von Metadaten.

<Meta name="vss" value="{version}27{/version}" />

Die Infor­mation wird später beim Laden von alten Dokumenten verwendet. Das DMS sollte nach dem Öffnen eines alten XML-Dokumentes immer eine Zuordnung je nach Erstel­lungs­datum von allen XML-Vorlagen zum Dokument finden können. Als Schema könnte man alles in einer Tabelle darstellen:

Nummer oder symbo­li­scher Name des Releases von XML-Vorlagen

Ablauf der Textverarbeitung

release1 Aktuelle_XML_Vorlage_vom_2008-02–01_XX-XX-XX.zip
Die Dokumente werden im Zeitraum von 01.02.2008 bis 07.02.2008 erstellt und gespei­chert. Alle Dokumente, wenn nichts anderes von der Verwaltung vorge­geben, sollen nur die XML-Bausteine aus der Auslie­ferung „Aktuelle_XML_Vorlage_vom_2008-02–01_XX-XX-XX.zip“ verwenden.
release2 Aktuelle_XML_Vorlage_vom_2008-02–07_XX-XX-XX.zip
Die Dokumente werden im Zeitraum von 07.02.2008 bis 14.02.2008 erstellt und gespei­chert. Alle Dokumente, wenn nichts anderes von der Verwaltung vorge­geben, sollen nur die XML- Bausteine aus der Auslie­ferung „Aktuelle_XML_Vorlage_vom_2008-02–07_XX-XX-XX.zip“ verwenden.
release… Aktuelle_XML_Vorlage_vom_.…._XX-XX-XX.zip
…..
releaseNN Aktuelle_XML_Vorlage_vom_2008-10–15_XX-XX-XX.zip
Die Dokumente werden im Zeitraum von 15.10.2008 bis TT.MM.JJJJ erstellt und gespei­chert. Alle Dokumente, wenn nichts anderes von der Verwaltung vorge­geben, sollen nur die XML- Bausteine aus der Auslie­ferung „Aktuelle_XML_Vorlage_vom_2008-10–15_XX-XX-XX.zip“ verwenden.

 

Die Nummer oder eine textuelle Bezeichnung der Auslie­ferung (kurz „release“ oder „schnitt“) soll als Metada­tensatz zum Dokument gespei­chert werden. Später, beim Laden des Dokumentes, gibt diese Bezeichnung vor, welche Version der noch nicht geladenen XML-Vorlagen in dieses Dokument geholt bzw. bei Bedarf aktua­li­siert werden sollte.

Allen Bezeich­nungen des Releases werden alle enthal­tenen XML-Vorlagen mit eigenen Versionen zugeordnet. Falls ein Release nur eine Delta der XML-Vorlagen enthielt, diese wird auch mit gleichem Prinzip markiert. Wenn bei der Inter­pre­tierung des Dokumentes kein XML-Baustein in der Bezeichnung des Releases gefunden wird, geht DMS automa­tisch auf eine Version der Bezeichnung runter.

Wofür benötigt man ein Dokumen­ten­ver­wal­tungs­system (DMS)?

Das DMS dient der revisi­ons­si­cheren und vor allem auch platz­spa­renden Ablage von Faxen, E‑Mails sowie der digita­li­sierten Eingangspost und auch Dokumenten, wie zum Beispiel Belegen, Rechnungen, Versi­che­rungs­un­ter­lagen und Verträgen. Das DMS sorgt ebenfalls dafür, dass man diese Unter­lagen zu einem späteren Zeitpunkt schnell und effizient wieder auffinden kann. Natürlich könnte man auch ohne ein Dokumen­ten­ver­wal­tungs­system auskommen, möchte man aber die Geschäfts­pro­zesse verein­fachen, digita­li­sieren und beschleu­nigen, ist der Schritt hin zum Dokumen­ten­ver­wal­tungs­system tatsächlich der richtige. Das Wichtigste ist, dass alle Dokumente revisions- und rechts­sicher aufbe­wahrt sind und auch schnell wieder­ge­funden werden können.

Welche Folgen hat es, wenn man dieses System nicht nutzt?

Wenn man sich für ein Dokument­ma­nage­ment­system entscheidet, dann sollte dieses auch genutzt werden. Die Dokumente müssen ins System einge­bracht werden, damit sie im Dokumen­ten­system verwaltet werden können. Wenn man dieses Dokument­ma­nage­ment­system einführt, sollte es von allen Mitar­beitern genutzt werden. Es zeigt sich aber in der Regel, dass nicht jeder Mitar­beiter eine Lizenz erhält, was nicht an den Lizenz­preisen liegt, sondern an den Folge­kosten. Es ist unumgänglich, dass jeder Mitar­beiter auf dieses System geschult wird, damit es auch optimal angewendet wird. Dabei können mitunter hohe Aufwen­dungen entstehen. Wird aber ein Dokument­ma­nage­ment­system einge­führt, aber nicht genutzt, bzw. nicht in der Form, wie es eigentlich vorge­sehen ist (also mit Dokumenten befüllt), ist das Vorhaben schnell zum Scheitern verur­teilt. Die wichtigen Daten sind damit nicht im System abgelegt. Tritt aber der Idealfall ein und es wird genutzt, dann können die Daten­server ersetzt werden. Nur wenn das der Fall ist, ist auch sicher gestellt, dass sich ein DMS umsetzen lässt.

Fortsetzung folgt.

In diesem Beitrag möchten wir einige Vorteile der JavaFX-Bibliothek erläutern, die besonders im Bezug auf das Userin­terface eine Rolle spielt.
Als einer der wichtigen Vorteile der JavaFX Bibliothek gilt die Möglichkeit der Nutzung von Styles (CSS), die uns aus dem WWW bekannt sind.
Dadurch verliert sich die Abhän­gigkeit zu der Bibliothek Look & Feel. Man kann jedoch selbst das Aussehen der Appli­kation bestimmen, was auch ziemlich flexibel und schön möglich ist. Die Gestaltung kann dynamisch erfolgen, eine Animation beinhalten oder auch 3D Grafik.
Durch die Benutzung der Style-Konzeption ist es nun möglich, die Appli­ka­tionen mit so genannten „Skins“ zu erstellen, durch die das Aussehen der Appli­kation komplett von der Business­logik losgelöst wird und mehr Indivi­du­altät erhält. Solche indivi­du­ellen Skins können sogar separat von einem Designer erstellt werden.

Erstellen wir ein einfaches Beispiel eines Dialog­fensters mit einem Button:

public class JavaFXDialog1 extends Application {
    @Override
    public void start(Stage stage) {
        final VBox vbox = new VBox();
        final Button button = new Button("test");
        vbox.getChildren().addAll(button);
        final Scene scene = new Scene(vbox, 150, 100);
        stage.setScene(scene);
        stage.show();
    }
  
    public static void main(String[] args) {
        launch(args);
    }

avafx and css styles 1

Styles kann man unter­schiedlich anwenden:
1) Unmit­telbar im Code, um z.B. die Schrift­farbe in dem Button zu ändern:

button.setStyle("-fx-text-fill: red");

avafx and css styles 2

2) Mit Hilfe einer CSS-Datei, auf die die Klasse Scene ausge­richtet werden soll:
Dafür wird eine Datei mit der Erwei­terung .css erstellt und unter dem Projekt­ver­zeichnis abgelegt, z.B. /css/styles.css.
Inhalt der Datei:

.button {
    -fx-text-fill: blue;
}

Dabei ist es sehr wichtig, die Entwick­lungs­um­gebung so einzu­richten, dass sie diese CSS-Dateien beim Bilden der Appli­kation auch mitkopiert.
Unter IntelliJ IDEA wird es beispiels­weise folgen­der­maßen gemacht:

avafx and css styles 3

Nun ist alles fertig, um die Style-Datei einzubinden:

scene.getStylesheets().add((getClass().getResource("/css/styles.css")).toExternalForm());

Wir starten das Projekt und bekommen folgendes Dialogfenster:
avafx and css styles 4

Instruktion .button in der CSS-Datei sagt aus, dass nun alle Knöpfe eine blaue Schrift­farbe haben werden:

final Button button1 = new Button("button1");
final Button button2 = new Button("button2");
vbox.getChildren().addAll(button1, button2);

avafx and css styles 5

Und was, wenn das nicht das ist, was wir brauchen? Was, wenn wir einen konkreten Knopf definieren wollen?
3) Abhilfe schafft die userbe­zogene Definition des Knopf-Styles:
In styles.css schreiben wir:

.button1 {
    -fx-text-fill: green;
}

Und im Code:

button1.getStyleClass().add("button1");

Das Dialog­fenster sieht so aus:
avafx and css styles 6

Nun haben alle Knöpfe, die mit der Style-Klasse verbunden sind, grüne Schrift­farbe, wobei die Methode add() uns dabei Hinweise gibt, dass wir mehrere von solchen Styles hinzu­fügen können, wodurch verschiedene Element­ei­gen­schaften erweitert, vorde­fi­niert oder überladen werden.
4) User-Style kann man auch durch den so genannten ID definieren:

In der styles.css schreiben wir:

#button2 {
    -fx-text-fill: yellow;
}

Und im Code:

button2.setId("button2");

Als Ergebnis bekommen wir folgendes Dialogfenster:

avafx and css styles 7

D.h. alle Elemente mit der gleichen ID sehen gleich aus.

Was kann man sonst noch Inter­es­santes mit den Styles machen?

Styles können auch die so genannten Verhal­tens­trigger bearbeiten, die aus der XAML Welt kommen.
Wenn wir bei dem Beispiel mit dem Knopf bleiben, gehören zu diesen Triggern solche Ereig­nisse der GUI wie Fokus, Selektion, Mousedown, Mouseover usw. also alles, was man nicht im Dialog­fenster haben möchte. Es beinhaltet nur den Buisiness­login bei den kunden­sei­tigen Änderungs­wün­schen und es wird nur die CSS-Datei geändert und nicht die Logik.
So kann man z.B. mit der folgenden CSS-Definition die Farbe des Knopfes ändern, wenn der User mit der Maus darüber fährt.

.button:hover {
    -fx-background-color: orange;
}

So sieht das Dialog­fenster bei Mouseover aus:

avafx and css styles 8

Wie bereits oben erwähnt, führt das zum gleichen Verhalten von allen Button-Klassen. Mit diesem Code:

.button1:hover {
    -fx-background-color: orange;
}

werden die Trigger nur für die Elemente angewendet, die auf die Klasse «button1» verweisen.

Diese Vorge­hens­weise kann man bei vielen Trigger anwenden, bei Knöpfen gibt es z.B. auch noch foused, selected oder presset.

Leider kann das nicht direkt im Code genutzt werden:

button.setStyle(":hover -fx-text-fill: red");

Vielleicht wird diese Möglichkeit in der Zukunft durch JavaFX Developer realisiert.

Wozu brauchen wir das alles? Im Internet kann man noch eine Reihe an Beispielen finden, die deutlicher sind als dieses. Das Ziel des Beitrags war nicht, diese zu kopieren. Uns geht es darum, dass die Konzeption von Syles und Trigger  auch für den eigenen Bedarf erweitert werden kann, das ist für uns von Interesse.

Als Beispiel können wir folgende Ausgangs­si­tuation betrachten:
wir wollen mit JavaFX eine visuelle Kompo­nente umsetzen, die für die Auswahl der Größe einer im Text einge­fügten Tabelle dienen soll. Das Aussehen der Kompo­nente, das Farbschema, die Größe usw., sollen dabei kein Bestandteil der Business­logik der Kompo­nente sein, sondern über eine externe CSS-Datei konfi­gu­rierbar sein.

Das sollte ungefähr so aussehen:

avafx and css styles 9

Der User geht mit dem Mauszeiger über die Tabelle und sieht seine ausge­wählten Elemente, in dem Fall eine Tabelle mit 7 x 8 Zellen. Beim Klick auf die Kompo­nente sollte die Auswahl an das Programm übermittelt werden, um eine entspre­chende Tabelle einzufügen.
Sicherlich kann man auf die Auswahl über den Code reagieren, aber was wenn der eine Kunde eine bestimmte Farbe bevorzugt, der andere aber ganz andere Farben bevorzugt? Möglich ist auch, dass das Farbschema durch ein «Skin» oder sonst wie vorde­fi­niert wird – was dann?

Hier wird nur eine Kompo­nente für die Zellen­se­lektion benötigt, um deren Aussehen es an dieser Stelle aber nicht gehen soll.

Hier können wir auf das voran­ge­gangene Beispiel mit dem Trigger «hover» für den Button anknüpfen. Der wirkt aller­dings für jede Zelle, wenn man mit dem Mauszeiger über sie fährt. Die Zellen, die der Mauszeiger verlassen hat, entsprechen dem Trigger nicht mehr und fallen somit aus der Auswahl. Wie können wir den gesamten Bereich ausge­wählt behalten?

Für die Lösung dieser Aufgabe wird ein eigener Trigger erstellt, der auf eine bestimmte Eigen­schaft des Objektes reagiert, z.B. «bin im Diapason der Selektion» oder inRange, die wir folgen­der­maßen in der CSS-Datei definieren können:

.MyCell:inRange {
    -fx-border-width: 0.5;
    -fx-border-color: #ffffff;
    -fx-background-color: lightskyblue
}

An der Stelle muss man aber sagen, dass dies ist keine einfache Aufgabe ist. Zudem ist die Lösung für die JavaFX Versionen 1.7 und 1.8 gänzlich unter­schiedlich. Für die Lösung in der Version 1.7. sind wir auf die Nutzung einer Menge der depre­cated-Methoden angewiesen.

Für den Anfang schauen wir uns die Kompo­nente an:

public class JavaFXDialog2  extends Application {
    @Override
    public void start(Stage stage) {
        final VBox vbox = new VBox();
        final GridPaneEx table = new GridPaneEx();
        table.init(10, 10);
        final Label label = new Label();
        label.setMaxWidth(Double.MAX_VALUE);
        label.setAlignment(Pos.CENTER);
        label.setTextAlignment(TextAlignment.CENTER);
        label.setStyle("-fx-padding: 3 0 5 0");
        label.textProperty().bind(table.text);
        vbox.getChildren().addAll(label, table);
        final Scene scene = new Scene(vbox, 350, 300);
        scene.getStylesheets().add((getClass().getResource("/css/styles.css")).toExternalForm());
        scene.setFill(null);
        stage.setScene(scene);
        stage.show();
    }
 
 
    public static void main(String[] args) {
        launch(args);
    }
 
 
    private void fireCreateTable(final int cols, final int rows){
        System.out.println("cols = " + cols + ", rows = " + rows);
    }
 
 
    protected class GridPaneEx extends GridPane {
  
        public final StringProperty text = new SimpleStringProperty("cancel");
        private int cols;
        private int rows;
  
        public GridPaneEx(){
            this.setOnMouseExited(new EventHandler() {
                @Override
                public void handle(MouseEvent mouseEvent) {
                    text.setValue("cancel");
                    deselectAll();
                }
            });
        }
  
        public void init(final int cols, final int rows){
            getChildren().clear();
            this.cols = cols;
            this.rows = rows;
            for (int col = 0; col < cols; col++){
                for (int row = 0; row < rows; row++){
                    final Button rect = new Button();
                    rect.setMinSize(30, 10);
                    add(rect, col, row);
                    final int selectedCol = col;
                    final int selectedRow = row;
                    rect.setOnMouseMoved(new EventHandler() {
                        @Override
                        public void handle(MouseEvent mouseEvent) {
                            selectRange(selectedCol, selectedRow);
                            text.setValue((selectedCol + 1) + " x " + (selectedRow + 1));
                        }
                    });
                    rect.setOnAction(new EventHandler() {
                        @Override
                        public void handle(ActionEvent actionEvent) {
                            fireCreateTable(selectedCol + 1, selectedRow + 1);
                            deselectAll();
                        }
                    });
                }
            }
            deselectAll();
        }
  
        private Node getNodeFromGridPane(int col, int row) {
            for (Node node : getChildren()) {
                if (GridPane.getColumnIndex(node) == col && GridPane.getRowIndex(node) == row) {
                    return node;
                }
            }
            return null;
        }
  
        private void selectCell(int col, int row, final boolean select){
            final Node node = getNodeFromGridPane(col, row);
            if (select){
                node.setStyle("-fx-border-width: 0.5; -fx-border-color: #ffffff; -fx-background-color: lightskyblue");
            } else {
                node.setStyle("-fx-border-width: 0.5; -fx-border-color: #000000; -fx-background-color: #ffffff");
            }
        }
  
        public void deselectAll(){
            for (int col = 0; col < cols; col++){
                for (int row = 0; row < rows; row++){
                    selectCell(col, row, false);
                }
            }
        }
        private void selectRange(int selectedCol, int selectedRow){
            deselectAll();
            for (int col = 0; col <= selectedCol; col++){
                for (int row = 0; row <= selectedRow; row++){
                    selectCell(col, row, true);
                }
            }
        }
    }
}

Besonders inter­essant ist die Methode selectCell, in der die Zellen­färbung unmit­telbar im Code reali­siert wird:

Für normale Zellen:

node.setStyle("-fx-border-width: 0.5; -fx-border-color: #000000; -fx-background-color: #ffffff");

Für Zellen im ausge­wählten Bereich:

node.setStyle("-fx-border-width: 0.5; -fx-border-color: #ffffff; -fx-background-color: lightskyblue");

Weil es in der Aufga­ben­be­schreibung steht, dass klare Farben­zu­weisung unmöglich ist, versuchen wir die mit Hilfe eines eigenen Styles in styles.css zu definieren:

#MyCellNormal {
    -fx-border-width: 0.5;
    -fx-border-color: #000000;
    -fx-background-color: #ffffff;
}
 
 
#MyCellInRange {
    -fx-border-width: 0.5;
    -fx-border-color: #ffffff;
    -fx-background-color: lightskyblue
}

Und in der Methode selectCell:

private void selectCell(int col, int row, final boolean select){
            final Node node = getNodeFromGridPane(col, row);
            if (select){
                                node.setId("MyCellNormal");
            } else {
                                node.setId("MyCellInRange");
            }
        }

Schon besser, nicht war? D.h. wenn der Kunde mit der Farbwahl unzufrieden sein sollte, kann man sie direkt in der Datei styles.css ändern. Die Logik der Kompo­nente bleibt dabei unverändert.

Aller­dings gibt es eine noch elegantere Lösung der Aufgabe: Platzieren wir in styles.css noch zusätzlich 2 Sytles:

.MyCell {
    -fx-border-width: 0.5;
    -fx-border-color: #000000;
    -fx-background-color: #ffffff;
}
 
 
.MyCell:inRange {
    -fx-border-width: 0.5;
    -fx-border-color: #ffffff;
    -fx-background-color: lightskyblue
}

Das bedeutet, dass die Zellen sich auf den Style «MyCell» orien­tieren und wenn der Trigger «inRange» greift, analog zu «hover» oder «presset», ändert sich die Farbe entsprechend.
Aber wie bringen wir der Zelle bei, den Trigger zu starten?
Da wir in unserem Beispiel für die Zellen, Button-Elemente nutzen, ist es erfor­derlich ihr Verhalten in der so genannten Pseudo-Klasse neu zu definieren. In JavaFX 1.7 wird das so gemacht:

protected static class RangeButton extends Button {
        public RangeButton(){
            getStyleClass().add("MyCell");
        }
 
 
        private BooleanProperty inRange = new BooleanPropertyBase() {
 
 
            @Override
            protected void invalidated() {
                impl_pseudoClassStateChanged("inRange");
            }
 
 
            @Override
            public Object getBean() {
                return RangeButton.this;
            }
 
 
            @Override
            public String getName() {
                return "inRange";
            }
        };
 
 
        public boolean isInRange() {
            return inRange.get();
        }
 
 
        public void setInRange(boolean value) {
            inRange.set(value);
        }
 
 
        private static final long IN_RANGE_PSEUDOCLASS_STATE = StyleManager.getInstance().getPseudoclassMask("inRange");
 
 
        @Override
        public long impl_getPseudoClassState() {
            long mask = super.impl_getPseudoClassState();
            if (isInRange()) mask |= IN_RANGE_PSEUDOCLASS_STATE;
            return mask;
        }
    }

Wie wir sehen, sind alle Methoden «…Pseudo­Class…» – deprecated.
Jetzt nutzen wir statt Button unseren Range­Button. Und die Methode selectCell sieht nun so aus:

private void selectCell(int col, int row, final boolean select){
            final Node node = getNodeFromGridPane(col, row);
            ((RangeButton)node).setInRange(select);
        }

D.h. die Änderung der Feldei­gen­schaft «InRange» führt dazu, dass der Style-Trigger greift und die Farbe der ausge­wählten Zellen sich entspre­chend ändert.
Das ist genau das, was wir brauchen!
In JavaFX 1.7 funktio­niert das. In JavaFX 1.8 ist das leider verboten. Der Code ist nicht mehr kompi­lierbar sobald JVM 1.8 hinzu­ge­schaltet wird.
Was bietet uns dann die neue Version an der Stelle?
Wie bereits erwartet, wurden die depre­cated Methoden entfernt und die Archi­tektur verein­facht. Jetzt reicht es daher aus, wenn wir folgendes tun:

protected static class RangeButton extends Button {        protected final PseudoClass pcInRange = PseudoClass.getPseudoClass("inRange");
 
 
        public RangeButton(){
            getStyleClass().add("MyCell");
        }
 
 
        protected final BooleanProperty inRange = new BooleanPropertyBase() {
 
 
            @Override
            protected void invalidated() {
                pseudoClassStateChanged(pcInRange, getValue());
            }
 
 
            @Override
            public Object getBean() {
                return RangeButton.this;
            }
 
 
            @Override
            public String getName() {
                return "inRange";
            }
        };
 
 
        public boolean isInRange() {
            return inRange.get();
        }
 
 
        public void setInRange(boolean value) {
            inRange.set(value);
        }
    }

Alles funktio­niert wie bisher.
Man kann den Code noch etwas vereinfachen…:

protected static class RangeButton extends Button {
        protected final BooleanProperty inRange;
        public RangeButton(){
            getStyleClass().add("MyCell");
            final PseudoClass pcInRange = PseudoClass.getPseudoClass("inRange");
            inRange = new SimpleBooleanProperty();
            inRange.addListener(new ChangeListener() {
                @Override
                public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                    pseudoClassStateChanged(pcInRange, newValue);
                }
            });
        }

…und die Methode entspre­chend ändern:

private void selectCell(int col, int row, final boolean select){
            final Node node = getNodeFromGridPane(col, row);
            ((RangeButton)node).inRange.setValue(select);
        }

Zusam­men­fassung: Mit Hilfe der beschrie­benen Lösung auf JavaFX ist es möglich, spezielle userbe­zogene Eigen­schaften der Kompo­nenten zu erstellen und diese mit den Styles zu verknüpfen,. Das ist besonders bequem, wenn die Anfor­derung besteht, die Business­logik komplett von der GUI zu abstrahieren.

Bei der Entwicklung einer Software sind Tests zur Quali­täts­si­cherung ein sehr wichtiger Arbeits­ab­schnitt. Hierbei werden verschiedene Sicher­heits­aspekte einer erstellten und weiter­ent­wi­ckelten Software durch unter­schied­liche Sicher­heits­an­for­de­rungen berück­sichtigt. Dabei spielen Tests im Risiko­be­reich, ein mögliches Keyword-Driven Testing oder Data Driven Testing mit verschie­denen Verfahren und Teststufen eine wichtige Rolle. Diese Tests werden stets vor einer endgül­tigen Abnahme und Freigabe zur Nutzung durch­ge­führt. Im Rahmen der Quali­täts­si­cherung wird dabei zwischen analy­ti­schen und konstruk­tiven QS-Maßnahmen unter­schieden. Weiter­lesen

Sammlung der statis­ti­schen Infor­ma­tionen über die Dokumente

In einem Dokumen­ten­ver­wal­tungs­system werden in der Regel Verträge, Versi­che­rungen, Rechnungen und Belege, E‑Mails und Faxe unter­ge­bracht und nach Wichtigkeit sortiert. Wird ein Workflow Management einge­führt, werden die Arbeits­ab­läufe, die in einer Organi­sation etabliert sind, eventuell auch organi­sa­ti­ons­über­greifend festgelegt. Dies setzt aber voraus, dass die Prozess­ab­läufe schon vor der Einführung des Systems festgelegt und analy­siert werden. Aus diesem Grund ist eine Festlegung der Workflows erfor­derlich, auch für die Abläufe der elektro­ni­schen  Bearbeitung. Erst wenn alles festgelegt ist, kann auch die Festlegung der daten­schutz­recht­lichen Sicher­stellung der Bearbei­tungswege garan­tiert werden. Erst wenn die komplette Bearbeitung elektro­nisch durch das Workflow-Management gesteuert wird, sind die Arbeits­ab­läufe vor der Nutzung dieses Systems hervorzuheben.

Welche DMS Software wird auf dem Markt angeboten?

Es bieten sich unter­schied­liche Software-Systeme für die Dokumen­ten­ver­waltung an. Zum einen sind es die kommer­zi­ellen Software­an­gebote, zum anderen gibt es die freien Software Systeme für DMS. Diese bieten sich als gebüh­ren­freie Open-Source Lizenzen an. Die freie Software kann von jedem Unter­nehmen selbst instal­liert und genutzt werden. Es gibt aller­dings auch Anbieter, die sich auf diese freie Software spezia­li­siert haben und auf der Basis der freien Software Dienstleistungen erbringen, die wiederum ihrer­seits kosten­pflichtig sind. Bei den freien Systemen ist vorteilhaft, dass diese den Bedürf­nissen des Anwenders angepasst werden können und Fehler auch automa­tisch behoben werden können – dadurch kann das Inves­ti­ti­ons­vo­lumen um ein Vielfaches gesenkt werden. Das so freiwer­dende Budget kann für wichtigere Anpas­sungen genutzt werden. Es stehen folgende Software Systeme zur Verfügung:

Freie Software Programme

Alfresco ist eine Community Edition, Agorum core – open,
Bitfarm-Archiv, LogicalDOC ist ebenfalls eine Community Edition,
Nuxeo EP, PLMWORX, Open-Xchange

Die Kommer­zi­ellen Software Programme

Alfresco (Enter­prise Edition), Agorum core (Pro), BSCW, dotiga, Document Control Center
Fabasoft Folio, Elektro­ni­scher Leitz Ordner, LogicalDOC (Enter­prise Edition), Main Pyrus DMS,
Microsoft Share­Point Server besitzt nur Teilfunk­tionen eines DMS, IBM FileNet, Xerox DocuShare

Sollte man selber eine DMS-Software entwi­ckeln oder besser eine bereits bestehende Software nutzen?
Wenn man die Software-Entwicklung beherrscht, steht dem sicherlich nichts im Wege, aber in der Regel bietet sich eine günstige und anpassbare DMS Software durchaus an. Freie Software bietet sehr viele Vorteile.
Es besteht aber auch die Möglichkeit, sich eine eigene Software von einem Unter­nehmen bezie­hungs­weise einem Software-Entwickler erstellen zulassen. Diese kann dann natürlich auch genau auf die Bedürf­nisse und die Arbeits­ge­wohn­heiten des Unter­nehmens angepasst werden. So müssen sich die Mitar­beiter nicht umstellen und können ihre gewohnten Arbeits­weisen beibe­halten. Das wiederum ist aber auch mit den freien Software Systemen möglich. Letztlich ist es eine echte Kosten-Nutzen-Frage.

Fortsetzung folgt.