RRZE – Projekte & Prozesse (P&P)

Das Blog der RRZE Stabsstelle "Projekte & Prozesse"

Content

Sortierbare Elemente in Tapestry per jQuery UI

Problembeschreibung

 
English Version
Zur Sortierung von Elementen in einem Webfrontend kann man sich verschiedene Realisierungen vorstellen. Beispielsweise könnte man für jedes Element eine Textbox bereitstellen, in denen der Benutzer den Index innerhalb der Sortierreihenfolge definiert. Das ist zwar sehr barrierefrei, aber auch unhandlich, wenn man sich vorstellt, dass in einer bestehenden Sortierung das letzte Element weit nach oben verschoben werden soll, da dann viele Indizes angepasst werden müssen. Eine andere Realisierung wären Links mit denen die Elemente jeweils eine Position nach oben oder unten verschoben werden können. Das erfordert jedoch häufiges Neuladen der Seite und ist für den Benutzer nicht sonderlich ästhetisch anzusehen.

Daher wurde für eine konkrete Realisierung des Problems in FAU.ORG auf die wunderbare Welt der AJAX/Javascript Komponenten von jQuery zurückgegriffen. Konkret auf die Komponenten von jQuery UI. Diese Komponentensammlung umfasst sowohl Interactions (also Elemente wie Draggable, Droppable, Sortable, etc.) als auch Widgets (Datepicker, Progressbar, etc.). Die Sortable-Komponente entsprach genau den Anforderungen des oben beschriebenen Problems.

Integration von jQuery:Sortable in Tapestry

Zunächst müssen die notwendigen Javascript-Bibliotheken eingebunden werden:
[html]<link type=”text/css” href=”${asset:jqueryui/themes/base/jquery.ui.all.css}” rel=”stylesheet” />
<script type=”text/javascript” src=”${asset:scripts/jquery-1.4.1.js}”></script>
<script type=”text/javascript” src=”${asset:jqueryui/ui/jquery.ui.core.js}”></script>
<script type=”text/javascript” src=”${asset:jqueryui/ui/jquery.ui.widget.js}”></script>
<script type=”text/javascript” src=”${asset:jqueryui/ui/jquery.ui.mouse.js}”></script>
<script type=”text/javascript” src=”${asset:jqueryui/ui/jquery.ui.sortable.js}”></script>[/html]
Optional kann man die sortierbaren Elemente (die als unordered List gerendert werden) als Kästen formatieren:
[html]<style type=”text/css”>
#sortable { list-style-type: none; margin: 0; padding: 0; float: left; margin-right: 10px; }
#sortable li { margin: 0 5px 5px 5px; padding: 5px; font-size: 1.0em; width: 350px; }
</style>[/html]
Danach wird die Liste um Sortierfähigkeit erweitert und ein Handler entwickelt, der die Sortierergebnisse speichert:
[javascript]<script type=”text/javascript”>
$(function() {
$(“#sortable”).sortable();
$(“#sortable”).disableSelection();
});

function storeOrder() {
var result = $(‘#sortable’).sortable(‘toArray’);
var context = “”;
for (var id in result) {
if (context == “”) {
context = result[id];
} else {
context = context + “_” + result[id];
}
}
window.location = “/${pageName}” + “.save/” + context;
}
</script>
[/javascript]
Schließlich wird die Liste selbst noch eingebunden und ein Speichernlink bereitgestellt:
[html]<ul id=”sortable”>
<li t:type=”loop” source=”elements” value=”element” id=”${element.id}”>${element.name}</li>
</ul>
<a href=”#” id=”prepare” onClick=”storeOrder()”>${message:save}</a>
<t:actionlink t:id=”save” context=”literal:dummy”></t:actionlink>[/html]
Die einzelnen Listenelemente werden durch invisible Instrumentation der Loop-Komponente von Tapestry erzeugt. Die erste Funktion im Javascript-Block sorgt für die Verschiebbarkeit per Maus der Elemente innerhalb der Liste und verbietet deren Selektierbarkeit.

Beim Klicken auf den HTML-Link wird lediglich die Javascript-Funktion storeOrder() aufgerufen. Diese erzeugt ein Array der IDs der Elemente in ihrer vor dem Klicken aktuellen Reihenfolge. Da diese Liste per ActivationContext an einen Actionhandler auf Tapestry-Serverseite übergeben werden soll, kommaseparierte Liste in diesem Kontext jedoch nicht zugelassen sind, wird die Liste in einen String umgewandelt, in dem die Element-IDs per Unterstrich voneinander getrennt vorkommen. Dies kann auf Serverseite durch ein simples String.split() wieder zerlegt werden. Man beachte, dass dafür ebenfalls ein Actionhandler auf Serverseite bereitgestellt werden muss. Dafür wurde der pseudo-Actionlink erzeugt. Der Redirect der storeOrder()-Funktion ruft den Actionhandler mit dem vorbereiteten ActivationContext schließlich manuell auf.

Demo

Eine Demo der Sortable-Komponente von jQuery UI ist hier zu finden.

Sortable Elements in Tapestry with jQuery UI

Problem description

There are many ways to realize sorting elements in a web frontend. One could provide a textbox for every element, which holds the index within the sorting order. This is barrier free to the fullest, but also very inconvenient. Imagine a ordered list, where the last element should be moved to the very top. With this technique almost all element indexes must be adopted. Another realization would be two links on every element. One to move itself upwards and one downwards. This requires a lot of page reloading and is not really state of the art.

To solve the concrete problem within the FAU.ORG project the wonderful AJAX/Javascript components of jQuery were used. More specific the components of jQuery UI. This collection of components includes Interactions (elements like Draggable, Droppable, Sortable, etc.) and Widgets (Datepicker, Progressbar, etc.). The sortable component matched exactly the requirements of the above mentioned problem.

Integration of jQuery:Sortable in Tapestry

First of all one has to include the required Javascript-libraries:
[html]<link type=”text/css” href=”${asset:jqueryui/themes/base/jquery.ui.all.css}” rel=”stylesheet” />
<script type=”text/javascript” src=”${asset:scripts/jquery-1.4.1.js}”></script>
<script type=”text/javascript” src=”${asset:jqueryui/ui/jquery.ui.core.js}”></script>
<script type=”text/javascript” src=”${asset:jqueryui/ui/jquery.ui.widget.js}”></script>
<script type=”text/javascript” src=”${asset:jqueryui/ui/jquery.ui.mouse.js}”></script>
<script type=”text/javascript” src=”${asset:jqueryui/ui/jquery.ui.sortable.js}”></script>[/html]
The next step comprises optional formatting of the elements (which are rendered as an unordered list):
[html]<style type=”text/css”>
#sortable { list-style-type: none; margin: 0; padding: 0; float: left; margin-right: 10px; }
#sortable li { margin: 0 5px 5px 5px; padding: 5px; font-size: 1.0em; width: 350px; }
</style>[/html]
Now the list is enriched to support sortability and a handler is developed, which stores the order of elements:
[javascript]<script type=”text/javascript”>
$(function() {
$(“#sortable”).sortable();
$(“#sortable”).disableSelection();
});

function storeOrder() {
var result = $(‘#sortable’).sortable(‘toArray’);
var context = “”;
for (var id in result) {
if (context == “”) {
context = result[id];
} else {
context = context + “_” + result[id];
}
}
window.location = “/${pageName}” + “.save/” + context;
}
</script>[/javascript]
Finally the list itself must be included and a link to store the changes provided:
[html]<ul id=”sortable”>
<li t:type=”loop” source=”elements” value=”element” id=”${element.id}”>${element.name}</li>
</ul>
<a href=”#” id=”prepare” onClick=”storeOrder()”>${message:save}</a>
<t:actionlink t:id=”save” context=”literal:dummy”></t:actionlink>[/html]
Every list element is created with invisible instrumentation of the Loop-component of Tapestry. The first function in the Javascript-block enables moving elements by mouse within the list and disables selections.

When clicking the HTML-link the storeOrder() Javascript-function is called. This function creates an array of the element-IDs in the most recent defined order. As the list will be handled over to an ActionHandler-function by ActivationContext on Tapestry server-side and comma-separated lists are forbidden within this context, the array is converted to a single string, where the IDs are separated by underscore. This string can easily be converted to an array again with the  String.split() Java-function.  Be aware, that therefore an ActionHandler has to be provided on server-side. To accomplish this a pseudo ActionLink is created within the Tapestry-Template. The redirect of the storeOrder()-function calls the ActionHandler with the given context manually.

Demo

A demo of the Sortable-component of jQuery UI can be found here.

Umwandeln von SVG-Grafiken in Visio-Dokumente per VBA

English Version
Die RRZE Icons werden ja bekanntlich im “Scalable Vector Graphics”-Format erstellt. Zur Verwendung der Icons in Visio kann dafür eine Stencil-Palette erstellt werden. Dafür müssen jedoch alle SVG-Grafiken in das Visio-Format umgewandelt werden. Dazu habe ich ein Skript in Visual Basic for Applications (VBA) – der Skriptsprache von Microsofts Office Produkten – erstellt, was diesen Prozess automatisiert für eine ganze Sammlung von Icons ausführt.
[vb]’Alle Variablen muessen vor ihrer Verwendung deklariert werden (sonst sucht man sich nen Wolf bei Fehlern)
Option Explicit

Sub Konvertieren()
Dim FSO
Dim SourceFolder
Dim SubFolder
Dim FileItem
Dim newFileName

Set FSO = CreateObject(“scripting.FileSystemObject”)
‘ Hier einfach den Basis-Ordner anpassen
Set SourceFolder = FSO.GetFolder(“E:\SVN\rrze-icon-set\trunk\visio\”)

For Each SubFolder In SourceFolder.SubFolders
‘ .svn-Ordner ignorieren
If (InStr(SubFolder.Path, “.svn”) = 0) Then
For Each FileItem In SubFolder.Files
‘ nur .svg-Dateien betrachten
If (Right(FileItem.Name, 4) = “.svg”) Then
newFileName = Replace(FileItem.Path, “.svg”, “.vdx”)
‘ keine existierenden vdx-Dateien überschreiben
If (Not FSO.FileExists(newFileName)) Then
‘ Neues Dokument beginnen
Application.Documents.AddEx “”, visMSDefault, 0
‘ Icon importieren
Application.ActiveWindow.Page.Import FileItem.Path
‘ Default-Dokument-Eigenschaften setzen
Application.ActiveDocument.Company = “RRZE”
‘ Datei mit gleichem Namen im vdx-Format abspeichern
Application.ActiveDocument.SaveAsEx newFileName, visSaveAsWS + visSaveAsListInMRU
‘ Dokument schließen
Application.ActiveDocument.Close
End If
End If
Next FileItem
End If
Next SubFolder

End Sub
[/vb]
Die Kommentare im Code erläutern die jeweilige Funktion der Zeile. Das Skript kann man einfach in den VBA-Skripteditor in Visio kopieren, den Wert des Basisverzeichnisses anpassen und ausführen (F5). Fertig.

Man könnte das Skript noch derart erweitern, dass es nach dem Basis-Ordner fragt. Dazu einfach hier oder hier nachlesen.

Batchprocessed conversion of svg-graphics to Visio-documents

The RRZE icons are designed in the “Scalable Vector Graphics”-format. For a convenient usage in Visio they can be collected as a stencil-set. Therefore their format has to be converted into the vdx-format. I wrote a script in Visual Basic for Applications (VBA) – the scripting language of Microsofts’ Office products – to convert a complete set of icons within a base folder.
[vb]’Declare all variables before usage to avoid typo errors
Option Explicit

Sub Convert()
Dim FSO
Dim SourceFolder
Dim SubFolder
Dim FileItem
Dim newFileName

Set FSO = CreateObject(“scripting.FileSystemObject”)
‘ The base folder MUST be defined here
Set SourceFolder = FSO.GetFolder(“E:\SVN\rrze-icon-set\trunk\visio\”)

For Each SubFolder In SourceFolder.SubFolders
‘ ignore .svn-folder
If (InStr(SubFolder.Path, “.svn”) = 0) Then
For Each FileItem In SubFolder.Files
‘ process .svg-files only
If (Right(FileItem.Name, 4) = “.svg”) Then
newFileName = Replace(FileItem.Path, “.svg”, “.vdx”)
‘ don’t overwrite existing vdx-files
If (Not FSO.FileExists(newFileName)) Then
‘ open a new document
Application.Documents.AddEx “”, visMSDefault, 0
‘ import icon into new document
Application.ActiveWindow.Page.Import FileItem.Path
‘ set default document properties
Application.ActiveDocument.Company = “RRZE”
‘ save as a file with same name in vdx-format
Application.ActiveDocument.SaveAsEx newFileName, visSaveAsWS + visSaveAsListInMRU
‘ cleanup
Application.ActiveDocument.Close
End If
End If
Next FileItem
End If
Next SubFolder

End Sub
[/vb]
The comments in the code describe the used functions. The script can simply be copied into the VBA-editor in Visio. Remember to set the base-folder correctly. Run the code within the editor (F5). As simple as that.

The script may be enhanced to use a dialog to ask for the base-folder. Simply read here or here about the usage of a FileDialog-Object.

Queries über mehrere Datenbanken in PostgreSQL

English Version

Einleitung

Manchmal muss man Daten aus mehreren Datenbanken miteinander vergleichen, importieren oder aktualisieren. Wenn nicht gerade umständlich ein Programm mit mehreren Datenquellen geschrieben werden soll, bleiben einem nur die Tools der Datenbank selbst. Im Fall von PostgreSQL sind das das Kommandozeilen-Interface psql oder die GUI pgAdmin. Beide sind jedoch nicht in der Lage Abfragen über mehrere Datenbanken abzusetzen. Das liegt schlicht daran, dass beim Verbinden zu einer Datenbank dessen spezifischen Systemkataloge geladen werden und Postgres anscheinend nicht in der Lage ist mehrere dieser Art gleichzeitig zu verwalten. Es gibt allerdings einen Ausweg: dblink. Dabei handelt es sich um eine SQL-Bilbiothek, die mit Postgres ausgeliefert wird und per Datenbank installiert werden kann. Mit Hilfe dieser Bibliothek ist es möglich, Daten aus einer anderen Datenbank abzufragen und andere SQL-Statements zu dieser abzusetzen.

Installation

Die Installation von dblink ist einfach: die Bibliothek liegt im contrib-Ordner der PostgreSQL Installation und wird so in eine Datenbank installiert:

psql -U postgres -d -f `pg_config --sharedir`/contrib/dblink.sql

Das Installieren unter dem Benutzer postgres ist empfehlenswert, da hierbei alle Berechtigungen für etwaige zusätzliche Installationen vorhanden sind. Durch `pg_config --sharedir` findet die Shell das Share-Verzeichnis, in dem der contrib-Ordner liegt. Man sollte sich nur immer im Hinterkopf behalten, dass die Bibliotheken des contrib-Ordners per Datenbank installiert werden (und damit auch Teil eines vollständigen dump sind).

Verwendung

Für Abfragen aus anderen Datenbank muss die dblink-Funktion verwendet werden. Diese wird einfach in der FROM-Clause verwendet:

Select * From dblink('dbname=fauorgdb', 'select id, fauorgpath from orgunit') as t1(id bigint, fauorgpath text);
-- Beispiel auf anderer Postgres Instanz:
Select * From dblink('hostaddr=dbsrv42 dbname=fauorgdb user=fauorg password=drowssap', 'select id, fauorgpath from orgunit') as t1(id bigint, fauorgpath text);

Der erste Parameter der dblink-Funktion definiert die Datenbankverbindung (in diesem Fall lediglich den Datenbanknamen), der zweite Parameter enthält die Anfrage. Der Alias-Teil der FROM-Clause t1(id bigint, fauorgpath text) muss leider verwendet werden, weil Postgres das Schema der abgefragten Daten nicht kennt und sonst schimpft. Eine as-Deklaration ist zwar SQL-Standard, jedoch ist die Definition der Feldtypen eine Postgres-Erweiterung. Da die Verwendung von Abfragen auf einer anderen Datenbank jedoch nicht zur alltäglichen Arbeit gehört, empfiehlt sich die Definition von Views:

create or replace view provisionierte_daten as
select * from dblink('dbname=fauorgdb', 'select id from orgunit') as t1(id bigint);

Die View wird einmal definiert und fertig. Damit lassen sich dann Abfragen der folgenden Art definieren:

select * from provisionierte_daten
except
select "FAUORGId" from "IMP_FAUORG";

Das ist sehr nützlich, um zu prüfen, ob zwei Datenbanken den gleichen Datenbestand haben.

Ultraschnieker Anwendungsfall: selektives Replizieren ODER ‘PostgrESB’ (FT)

Die Kombination aus sehr mächtigem Regelsystem und der Fähigkeit auf entfernten Datenbanken DML-Statements abzusetzen, ermöglicht (selektives) Replizieren von Daten. Hierbei geht es darum eine gesamte Datenbank (oder Teile davon) auf eine andere Datenbank zu replizieren. Alles was man dafür tun muss, ist

  1. das gesamte oder partielle Schema der primären Datenbank auf einer sekundären Datenbank zu installieren
  2. für alle Tabllen und DML-Operationen (INSERT, UPDATE, DELETE) eine Regel wie folgt zu erstellen:
    CREATE OR REPLACE RULE replic_insert AS
      ON INSERT TO  DO 
        SELECT dblink_exec(
          'dbname=test', 
          'insert into  (id, name) values (' || quote_literal(new.id) || ',' || quote_literal(new.name) || ');
        );
    

Das Beispiel funktioniert für eine Tabelle mit den Feldern id und name. Leider muss das Statement recht kompliziert aufgebaut werden, da die sekundäre Tabelle mit den Pseudonamen NEW und OLD nichts anfangen kann. Wird die Regel darüberhinaus mit einer WHERE-Bedingung definiert, lässt sich die Replikation selektiv einschränken. Des Weiteren muss das Schema nicht notwendigerweise gleich sein, da auch heterogene Datenbanken mit Daten versorgt werden können – vorausgesetzt man kennt das Schema und kann die Regel dementsprechend definieren. Anders ausgedrückt ist also nicht nur die Replikation einer Datenbank möglich, sondern vielmehr die Provisionierung eines Teils des Datenbestands in eine andere PostgreSQL Instanz (um den Kreis zum Titel dieses Abschnitts abzuschließen).

Probleme

Probleme bei der Verwendung traten bei mir lediglich mit Passwörtern auf. Die ‘Fremddatenbank’ benötigt ja ebenfalls Authentifizierung. In meinen Tests wurden lediglich Datenbanken auf derselben lokalen Postgres-Instanz abgefragt und ich habe den lokalen Zugriff in der pg_hba.conf auf trust gesetzt:

# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD
host    all         all         127.0.0.1/32          trust

Eine andere Möglichkeit besteht in der Verwendung der Passwortdatei.

Links

Querying multiple databases in PostgreSQL

Introduction

It is sometimes necessary to compare, import or update data from several databases. Unless you want to write a cumbersome program with several data sources, you are stuck with the database tools themselves. In PostgreSQL’s case, that is the command line interface psql or the GUI pgAdmin. Both of them are unable to process queries for several databases at once. The reason for this is simply that, upon connection to a database, its specific system catalogues are loaded, and Postgres seems unable to manage several of these at once. There is however, a way around this: dblink. This is an SQL library shipped with Postgres that can be installed via database. With this library, it is possible to query data from other databases and make SQL statements for these.

Installation

Installing dblink is easy: The library can be found in the PostgreSQL installation’s contrib folder. You can install it like this:

psql -U postgres -d -f `pg_config --sharedir`/contrib/dblink.sql

It is advisable to install as user postgres, as that gives you all the permissions necessary for possible additional installations. With `pg_config --sharedir`, the Shell finds the share directory that contains the contrib folder. Just keep in mind that the libraries within the contrib folder are installed via database (and are thus part of a complete dump).

Usage

For queries from other databases, you have to use the dblink function. You can use it with a simple FROM clause:

Select * From dblink('dbname=fauorgdb', 'select id, fauorgpath from orgunit') as t1(id bigint, fauorgpath text);
-- Example from another Postgres Instance:
Select * From dblink('hostaddr=dbsrv42 dbname=fauorgdb user=fauorg password=drowssap', 'select id, fauorgpath from orgunit') as t1(id bigint, fauorgpath text);

The dblink functions’s first parameter defines the database connection (in this case, the database name). The second parameter contains the query. The FROM clause’s alias part t1(id bigint, fauorgpath text) must be used because Postgres doesn’t know the queried data’s schema and starts whining otherwise. Although an as declaration would be SQL standard, definition of field types is part of the Postgres expansion. Since the use of queries in another database is probably not part of your everyday work, it is advisable to define Views:

create or replace view provisionierte_daten as
select * from dblink('dbname=fauorgdb', 'select id from orgunit') as t1(id bigint);

You only have to define the View once, and you are done. With this you can then use queries of the following kind:

select * from provisionierte_daten
except
select "FAUORGId" from "IMP_FAUORG";

This is very useful for checking if two databases have the same dataset.

Application deluxe: selective replicaion OR ‘PostgrESB’ (FT)

The combination of a very powerful set of rules and the possibility to put statements into remote databases, allows the selective replication of data. This means replicating a complete database (or parts thereof) into another database. All you have to do for this is

  1. installing the primary database’s complete or partial schema on the secondary database.
  2. create a rule for all tables and DML operations (INSERT, UPDATE, DELETE) as follows:
    CREATE OR REPLACE RULE replic_insert AS
      ON INSERT TO  DO 
        SELECT dblink_exec(
          'dbname=test', 
          'insert into  (id, name) values (' || quote_literal(new.id) || ',' || quote_literal(new.name) || ');
        );
    

The example works with a table containing the fields id and name. The statement needs to be rather complicated, as the secondary table cannot interprete the pseudo names NEW and OLD. If the rule is futher defined with a WHERE clause, the replication can be made very selective. In addition, the schemata don’t need to be identical, as you can also provide heterogenical databases with data – if you know the schema and can define your rule accordingly. In other words, this allows not only replication of a database, but also provisioning part of your dataset into another PostgreSQL instance.

Problems

The only problems I found were with passwords. The ‘foreign database’ needs authentication as well. In my tests, I only queried local databases within the same Postgres instance, and set the local access in pg_hba.conf to trust:

# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD
host    all         all         127.0.0.1/32          trust

Another possibility is the use of a password file.

Links

Isoliertes Classloading auf dem JBOSS AS

English Version

Durch Verwendung von Technologien wie Enterprise Java Beans (EJB) und Enterprise Service Bus (ESB) ist es heute ohne Weiteres möglich, lose gekoppelte und feingranular modulare Dienste zu entwerfen, die in Kollaboration eine verteilte Anwendung ausmachen. Einheiten des Entwurfs sind nicht mehr ganze Anwendungen, sondern klar abgegrenzte Dienste, die lokal oder entfernt benutzt werden können. Diese Dienste werden auf ein oder mehreren Applikationsservern (AS) deployed und können dort benutzt werden. Wenn die Dienste selbst auf Funktionen aus Bibliotheken zugreifen müssen, so kann es passieren, dass zwei unterschiedliche Dienste dieselbe Bibliothek in unterschiedlichen Versionen verwenden (müssen). Da beim Standard-Deployment allerdings alles von einem Classloader geladen und instanziert wird, tritt das Problem auf, dass nicht genau vorherzusagen ist, welche der beiden Versionen ein und derselben Bibliothek zuerst geladen wird. Darüberhinaus ist es ja gerade notwendig beide Versionen vorzuhalten, da sie in unterschiedlichen Contexten verwendet werden. Dies ist ohne weiteres Zutun nicht möglich. Daher bietet der JBOSS AS die Möglichkeit, Einheiten des Deployments (EJBs oder ESBs) so zu konfigurieren, dass sie von einem isolierten Classloader geladen werden. Damit ist es möglich die gleiche Bibliothek mehrfach zu laden (insbesondere mit unterschiedlichen Versionen), wenn dies gewünscht wird.

Eine Beispielkonfiguration für ESBs ist im Folgenden dargestellt:

[deployment.xml]
<jbossesb-deployment>
	<loader-repository>
		fauorg.esb.loader:loader=simple-scoped
		<loader-repository-config>java2ParentDelegaton=false</loader-repository-config>
	</loader-repository>
</jbossesb-deployment>

Die Datei sollte deployment.xml heißen und unter src/main/resources/META-INF abgelegt werden. Sie sorgt dafür, dass Klassen in folgender Reihenfolge geladen werden:

  1. /lib/ (aus dem verpackten ESBs)
  2. server/default/lib/

Dabei werden also lediglich Klassen aus dem server/default/lib/ Verzeichnis geladen, die nicht mit verpackt wurden. Der Name des JMX Classloader Objekts ist im Beispiel fauorg.esb.loader und sollte vom Entwickler festgelegt werden. Damit lassen sich auch mehrere Einheiten des Deployments in einem Classloader zusammenfassen.

Nähere Informationen hierzu finden sich hier. Eine Zusammenstellung von UseCases zum Thema isoliertes Classloading auf dem JBOSS AS gibts hier. Zum Aktivieren eines Loggers für den Classloader verfolgt man am besten diese Anleitung.

Isolated loading of classes on JBOSS AS

Using techology like Enterprise Java Beans (EJB) and Enterprise Service Bus (ESB), it is easily possible to design granular, losely connected modular services. In collaboration, these create distributed applications. Design units are no longer complete applications, but clearly separated services that can be used locally or remotely. These services are deployed on one ore more application servers (AS), and can be used there. If the services themselves need to access libraries, it is possible for two different services to use the same library in different versions. Since in standard deployment, everything is loaded and instanced by a classloader, the problem can occur that it becomes impossible to predict which library will be loaded first. It is furthermore necessary to keep both versions available, since they are used in different contexts. Without additional information, that is not possible. That is why JBOSS AS offers the possibility of configuring deployment units (EJBs or ESBs) in such a way that they are loaded by an isolated classloader. That makes it possible to load the same library multiple times (especially in different versions) if that is necessary.

Here is an exemplary configuration for ESBs:

[deployment.xml]
<jbossesb-deployment>
	<loader-repository>
		fauorg.esb.loader:loader=simple-scoped
		<loader-repository-config>java2ParentDelegaton=false</loader-repository-config>
	</loader-repository>
</jbossesb-deployment>

The file should be named deployment.xml and put in src/main/resources/META-INF. It ensures that classes are loaded in the following order:

  1. /lib/ (from the packaged ESBs)
  2. server/default/lib/

That means that only classes from the directory server/default/lib/ that weren’t packaged are loaded. The name of the JMX Classloader Object can be found in example fauorg.esb.loader and should be defined by the developer. This allows for several deployment units to be combined into one classloader

You can find further information here. A summary of UseCases regarding isolated classloading on the JBOSS AS can be found here. To activate logging for the classloader, follow these instructions.

Hibernate und Case-sensitive Tabellen-/Spaltennamen

English Version

Wenn Hibernate so konfiguriert ist, dass es das relationale Schema der Datenbank selbst erzeugt, werden alle Tabellen- und Spaltennamen derart erzeugt, dass sie lediglich aus Kleinbuchstaben bestehen. Das ist meines Erachtens auch sinnvoll, weil durch die Verwendung von Hibernate das zugrundeliegende Datenbankmanagementsystem einfach ausgetauscht werden kann. Einige Datenbanksysteme sind jedoch case-sensitiv und würden bei Verwendung einer ‘beliebigen’ Schreibweise Fehler erzeugen. Verfolgt man daher die Konvention alles klein zu schreiben, entstehen diese Probleme gar nicht. Des Weiteren ist es nicht empfehlenswert Tabellen- oder Spaltennamen zu vergeben, die sich einzig durch ihre Verwendung von Groß- und Kleinbuchstaben unterscheiden. Über die bessere Lesbarkeit von Tabellen- oder Spaltennamen mit gemischter Schreibweise (beispielsweise durch Verwendung von Binnenmajuskeln) lässt sich ohnehin streiten.

Hat sich ein Datenbankadministrator dennoch dafür entschieden Großbuchstaben in Bezeichnern eines relationalen Schemas zu verwenden, oder liegt das Datenbankschema schlicht bereits vor, wenn Klassen auf Relationen gemappt werden, kommt man nicht umher den Namen des Feldes oder der Tabelle explizit zu definieren. Ohne diese Definition würde Hibernate die Namen der Membervariablen und Klassen vollständig klein geschrieben verwenden und Datenbanksysteme, die Groß- und Kleinschreibung unterscheiden, würden Fehler erzeugen. Um den Namen des Bezeichners für die Datenbank zu definieren muss man lediglich den name-Parameter der Annotationen @Table und @Column (beide aus javax.persistence) verwenden und den vergebenen Namen in Backticks (`) setzen:

@Entity
@Table(name="`MyEntity`")
public class MyEntity {

  @Column(name="`StartDatum`")
  protected Date startDatum;

  ...
}

Das Mapping verwendet also eine Tabelle namens MyEntity, in der sich ein Feld namens StartDatum befindet.

Dank gilt Frank Tröger, der diesen Trick gefunden hat. Sollte man bei der Verwendung von Bezeichnern, die gleichzeitig Schlüsselwörter der Sprache SQL sind, Probleme haben, könnte die Verwendung von eckigen Klammern helfen.

Hibernate and case sensitive table and column names

If Hibernate is configured to create the relational database schema itself, all table and column names created will be lower case. I think this is reasonable in most cases, as you can simply switch the underlying database management system when using Hibernate. Several database systems are case sensitive, however, and would generate errors when using an ‘arbitrary’ notation. If you keep to the standard of writing everything lowercase, these problems won’t turn up. It is also not advisable to chose table or column names that only differ in their use of lower or uppercase letters. Whether or not table and column names with mixed notation (e.g. when using Camel Case) are better to read is open to discussion, anyway.

If the database admin decided to use upper case characters in relational schema names, or when the database schema is already existent when classes are mapped to relations, you won’t get around an explicit definition of fields or tables. Without this definition, Hibernate will use lower case for all member variables and classes, causing database system that differentiate between lower and uppercase to generate errors. To create a definition for a designator, simply use the name parameter of annotations @Table and @Column (both from javax.persistence) and put the name in backticks (`):

@Entity
@Table(name="`MyEntity`")
public class MyEntity {

  @Column(name="`StartDatum`")
  protected Date startDatum;

  ...
}

Mapping thus uses a table called MyEntity, with a field called StartDatum.

Thanks go to Frank Tröger, who found this trick. If you have problems using designators that are SQL key words, the use of square brackets might help.

Rekonstruktion von Dateisystemrechten in Linux

English Version

Ein Linux tut immer was man ihm sagt. Und wenn es erstmal fertig ist, gibt’s kein zurück. Das ist in den meisten Fällen keine schlechte Sache, denn man ist sich ja eigentlich immer sicher, dass man dies und das wirklich tun möchte 😉 Hin und wieder kann es jedoch vorkommen, dass einem Fehler unterlaufen und ein ‘Rückgängig’ ist nirgends zu finden. Um so einen Fall geht es nun hier. Ich wollte lediglich einem Verzeichnis und dessen Unterverzeichnissen Rechte auf alles (Lesen, Schreiben und Ausführen) geben.

chmod -R a+rwx DIR

Im ersten Versuch wurde ich noch nett gewarnt, dass das nicht ginge, weil mir das Verzeichnis nicht gehört. Kein Problem, da gibts ja noch den Superuser Account. Angemeldet, Befehl nochmals ausgeführt und zu spät bemerkt, dass sich das Terminal nach der Anmeldung als root im Wurzelverzeichnis / befand. Richtig dumm gelaufen. Jetzt können alle Benutzer Dinge lesen, schreiben und ausführen, auf die sie keinen Zugriff haben sollen. Rückgängig machen kann man das auch nicht. Also was tun? Eine Linux-Konsole ist ja bekanntlich das Schweizer Taschenmesser unter den Terminals, daher gibts bestimmt eine Möglichkeit. Dem ist auch so in Form von getfacl und setfacl. Alles was man noch tun muss, ist einen Rechner zu finden, der einigermaßen die gleiche Distribution und eine möglichst große Menge an gleich installierter Software besitzt. Danach meldet man sich am gesunden System an und sichert die Rechte auf die zu reparierenden Verzeichnisse:

getfacl -R DIR > /tmp/DIR.acl

Die DIR.acl enthält dann die ‘normalen’ Zugriffsrechte des Verzeichnisses ‘DIR’. Diese Datei muss dann aufs zu repariendene System übertragen werden. Dann dort anmelden und per

setfacl --restore=/tmp/DIR.acl

die Rechte in DIR rekonstruieren. Fehlende Dateien und Verzeichnisse werden natürlich ignoriert. Fertig. Alles wieder gut.

Reconstructing Data access rights in Linux

Linux always does as it’s told. And when it’s done, it’s done. Normally, that’s not a bad thing, after all, you know what you’re doing, don’t you? Every now and then, however, it might happen that you make a mistake, and there’s no ?Undo? Button in sight. That is what this article is about. Originally, all I wanted to do is grant access rights (read, write, execute) to one directory and all its subdirectories.

chmod -R a+rwx DIR

When I first tried this, I was warned that I couldn’t do it because the directory wasn’t mine. No problem, there’s still the Superuser Account. Logged in, executed the command and then realized too late that the the terminal was in the root directory after logging on as root. Tough luck. Now every user can read, write and execute whatever he wants. And there’s no way to undo it either. So what now? A linux console is, as is well known, the swiss army knife of terminals, so surely there’s a way to do it. And of course there is: getfacl and setfacl. All that is left to do is find a computer with roughly the same distribution and as much of the same software as possible. Log onto the ?healthy? system, save the rights for the directories in question:

getfacl -R DIR > /tmp/DIR.acl

DIR.acl now contains the ?normal? access rights for the directory ?DIR?. This file can be transferred to the system that needs repairing. Now log in there and use

setfacl --restore=/tmp/DIR.acl

to reconstruct the rights in DIR. Missing files and directories will be ignored, of course. And all is well again.

Inside FAU.ORG 2.0

English Version

Der neue Kern von FAU.ORG zeichnet sich durch moderne Technologien, schlankeres Design, verbesserte Modularität und neue Interoperabilität aus. Dieser Artikel stellt die neuen Kernkomponenten aus technischer Sicht vor und gibt einen kleinen Einblick in die Entwicklungsarbeit mit modernen Softwarekonzepten bei P&P.

 

Ein Dinosaurier in neuem Gewandt

Der neue FAU.ORG Kern setzt auf längst Bewährtes auf: relationale Datenbanken. Mit dem Java Content Repository System Jackrabbit als Persistierungs-Backend hatte man zwar Versionierung und dynamische Schemata, es ließen sich Versionen jedoch nur chronologisch geordnet erzeugen. Anders formuliert war es nicht ohne Weiteres möglich in der Vergangenheit zu arbeiten, insbesondere Änderungen der Vergangenheit auf die Gegenwart auswirken zu lassen.

Daher wurde für den neuen Kern ein Konzept entwickelt, was man aus der Videokodierung kennt. Hier werden nicht für jedes Bild (oder auch Frame) des Videos ganze Bilder (Keyframe) gespeichert, sondern nur in bestimmten Abständen. Alle dazwischen liegenden Frames speichern lediglich Änderungungsinformationen von einem Bild zum nächsten. Damit lassen sich die darzustellenden Informationen verlustfrei komprimieren.
In FAU.ORG findet das gleiche Prinzip seine Anwendung.
Der aktuelle Tag liegt immer als vollständige Information in einem klassischen Relationenschema vor. Dabei wurde schlicht davon ausgegangen, dass die meisten Zugriffe auf die Organisationsstruktur zum aktuellen Tag stattfinden und nicht in der Vergangenheit oder Zukunft. Alle Änderungen an Organisationseinheiten werden lediglich als Änderungsinformationen gespeichert. Im Gegensatz zu einem Videocodec allerdings mit dem neuen und dem alten Wert, damit man Zustände von Organisationseinheiten sowohl zeitlich vorwärts als auch rückwärts berechnen kann. Mit dieser Methode ist es möglich geworden, den Zustand des Organisationsbaums zu jedem beliebigen Zeitpunkt zu berechnen. Der Mehraufwand ist dabei verschwindend gering und liefert durch die Verwendung einer relationalen Datenbank mit bedacht gewählten Indizes gute Performance. Die Implementierung verwendet für den Zugriff auf die Datenbank Hibernate, wodurch weitestgehend objektorientierte Datenbankzugriffe verwendet werden konnten und das darunter liegende Datenbanksystem ohne Weiteres ausgetauscht werden kann. Durch Hibernate lassen sich aus einer Datenbank zu ladende Objekte direkt initialisieren, d.h. das Resultat der Abfrage an die Datenbank muss nicht mehr durch den Programmierer in die objektorientierte Welt übersetzt werden, sondern findet im Hibernate Framework selbst statt. Lediglich für die Berechnung eines Zustands in der Vergangenheit oder Zukunft werden die Attributwerte aus den Änderungstabellen geladen und per Java Reflection als Objekte instanziert.

 

Viele kleine Helfer

FAU.ORG wird nicht nur als zentrale Instanz die Organisationsstruktur der Universität Erlangen-Nürnberg verwalten, sondern eine Reihe externer, heterogener Systeme mit den verwalteten Daten provisionieren. Da jede Nacht für den aktuellen Tag der oben beschriebene Keyframe berechnet werden muss, werden gleichzeitig alle Änderungsereignisse, die an diesem Tag gültig werden ausgelesen. Diese Änderungen müssen an die externen Systeme verschickt werden. Um das System später leichter um neue anzubindende Systeme zu erweitern, strebt man eine möglichst generische Architektur an. Daher wurde der neue Kern von FAU.ORG ausschließlich als EJB-Komponenten (Enterprise JavaBean) implementiert. Diese Technologie birgt unter anderem die folgende Vorteile in sich:

  • Implementierung gegen Schnittstellen als Grundlage der Umsetzung
  • losere Kopplung der Komponenten durch kleinere Module, die per Annotationen miteinander verbunden werden können
  • leichteres Neu-Deployen von Komponenten on-the-fly im laufenden Betrieb, wenn Aktualisierungen oder Bugfixes vorliegen
  • einfachere Transaktionsverwaltung out-of-the-box
  • Trennung der Methoden, die durch interne und externe Aufrufe verwendet werden dürfen/können (lokale und entfernte Schnittstelle)
  • andere Projekte aus P&P können diese Komponenten einfach nutzen
  • problemlose Anbindung an einen Enterprise Service Bus (ESB), über den die Exportprozesse für externe Systeme leichter und generischer umgesetzt werden können

Durch die Verwendung von EJBs und dem ESB können Änderungen einfach als Nachrichten über den Bus verschickt und von den verschiedenen Treibern, die externe Systeme anbinden, entgegengenommen und verarbeitet werden. Weiterhin macht diese Methodik die Konfiguration dieser Prozesse einfacher.

 

FAU.ORG setzt also auf Altbewährtes, Aufgebohrtes, Brandneues und lose Gekoppeltes und ist damit gerüstet für alle zukünftigen Aufgaben. 🙂

Inside FAU.ORG 2.0

FAU.ORG’s new core is characterized by its use of modern technologies, a slim design, advanced modularity and new interoperability. This article introduces the new core components from a technical point of view and gives some insight into the developing process with modern software concepts at P&P.

A dinosaur with new clothes.

FAU.ORG’s new core uses a proven system: relational databases. While you already had versioning and dynamic schemata with Java Content Repository System Jackrabbit as a persistance backend, versions could only be created in a chronological order. In other words, you could not simply ?work in the past?, changes in the past with an effect on the present were rather difficult.

So a new concept was created for the core, adapted from video coding. Not every picture (or frame) in the video is saved as a complete picture (or keyframe), instead keyframes are only created in certain intervals. All the frames in between store only changes from one picture tothe next. That way, the information to be displayed can be compressed without loss. FAU.ORG implements the same principle.

The current day always contains the complete information in a classic relational schema. It is assumed that most will access the organisational structure on the current day and not at some point in the past or future. When changes are made to the organisational units, only those changes are stored. The difference to a video codec is that both the new and the old value are saved, so that organisational units’ states can be recreated both forward and backwards in time. With this method, it is possible to create the state of the organisational tree at any point in time. The additional workload is negligible, and by using a relational database with cautiously chosen indices, performance is good. The implementation uses Hibernate for accessing the database, so that most database accesses are object oriented, making sure that the basic database system can easily be exchanged. Hibernate allows direct initialisation of objects loaded from the database, i.e. results from accessing the database do not have to be translated into the object-oriented world, but are used directly within the Hibernate Framework. Attribute values are only loaded from the change tables and instanced via Java Reflection as objects when calculating a state in the future or past.

Lots of little helpers

FAU.ORG is not only going to manage the Universiy Erlangen-Nuremberg’s organisational structure as central instance, it will also provision a number of external, heterogenous systems with the managed data. Since the keyframe mentioned above needs to be constructed every night, all change events relevant for the next day are read. These changes need to be sent to external systems. To ease expansion into new systems later, it was aimed to keep the architecture as generic as possible. FAU.ORG’s core, e.g., was implemented exclusively as EJB components. This technology comes with the following advantages:

  • Implementation against interfaces as basis for the realisation.
  • Loose coupling of components through use of smaller modules, which can be connected via annotations.
  • Easier new deploying of components on-the-fly in a running system, when updates or bugfixes are available.
  • Easier transaction management out-of-the-box.
  • Separation of methods that can be called internally and externally (local and remote interfaces).
  • Other P&P projects can use these components easily.
  • Easy connection to an Enterprise Service Bus (ESB), so that export processes for external systems can be implemented easier and more generically.

By using EJBs and an ESB, changes can be transferred as messages through the bus, and can be accepted by the various drivers that connect external systems. Furthermore, this method makes configuration of the processes easier.

To sum up, FAU.ORG combines things well tried, finely tuned, brand new and losely coupled, and is thus ready for all future tasks.

Von einer Organisationsstruktur in Raum und Zeit

English Version

Als zentrale Komponente zur Verwaltung der Organisationsstruktur der Universität Erlangen-Nürnberg hat FAU.ORG nun das Release der zweiten Version erreicht. Seit der ersten Version hat sich hier einiges verändert. Die Benutzeroberfläche weist einige Neuerungen und verbesserte Features auf und die Kernkomponente wurde sogar komplett neu entwickelt. Dieser Blogartikel stellt das neue, bessere, schnellere und einfachere FAU.ORG vor.

Neue Datenhaltung

Die neu entwickelte Kernkomponente von FAU.ORG basiert nun auf einer relationalen Datenbank und bietet die folgenden Möglichkeiten:

  • Abbildung der benötigten Informationen in ein geeignetes Entity-Relationship-Schema
  • Persistierung der Daten und Änderungen auf diesen Daten (in separaten Relationen)
  • Unterstützung der temporalen Semantik für die Speicherungen von Änderungen in der Vergangenheit, Gegenwart und Zukunft
  • Volltextsuche in den Daten der Gegenwart

Zunächst wurde aus dem Datenmodell der ersten Version ein Entity-Relationship-Modell (ER-Modell) mit geringen Modifikationen erstellt. Da die meisten Attribute einer Organisationseinheit einwertige Daten enthalten, hätte man nur eine sehr geringe Anzahl an Relationen mit vielen Attributen entwerfen können. Dann wäre es jedoch nicht mehr so einfach gewesen, zusammen gehörende Daten zu gruppieren und später eine feingranulare Zugriffskontrolle auf bestimmte Attributgruppen zu implementieren. Über dies lässt sich mit mehreren Tabellen ein Mechanismus namens Lazy Loading nutzen. Hierbei werden aus der Datenhaltung nicht mehr alle verfügbaren Daten geladen, sondern nur noch das, was der Benutzer gerade benötigt. Das spart Hauptspeicher und ist in den meisten Fällen effizienter.

Neben den Relationen zur Speicherung der eigentlichen Daten, werden in FAU.ORG alle Änderungen von Beginn an auch als Änderungsereignisse in zwei eigenen Tabellen gespeichert. Ein Änderungsereignis bezieht sich auf das Erstellen, Modifizieren und Löschen von Daten einer Attributgruppe. Jedes Änderungsereignis enthält eine Reihe von Änderungseinträgen, die den alten und den neuen Wert des modifizierten Attributs, sowie das Datum der Änderung und das Datum, ab dem die Änderung gültig wird, enthalten. Dadurch ist es möglich in der Zeit zu reisen, da der Zustand jeder Organisationseinheit für jeden beliebigen Zeitpunkt aus dessen Änderungsereignissen berechnet werden kann.

Damit nicht bei jedem Zugriff der Zustand einer Organisationseinheit berechnet werden muss, enthält die Datenbank den Stand der Gegenwart in den eigentlichen Relationen zur Datenhaltung. Diese können schneller ausgelesen werden. Ändert der Benutzer etwas in der Zukunft werden für diese Änderungen lediglich Änderungsereignisse erstellt und gespeichert. Eine eigene Komponente liest jede Nacht die Änderungsereignisse aus, die für den aktuellen Tag gültig werden und setzt diese Änderungen im Stand der Gegenwart um. Damit wird der Zustand in den Tabellen immer up-to-date gehalten. Eine ähnliche Komponente wird in späteren Versionen externe Systeme mit diesen Änderungen provisionieren. Werden die Organisationsdaten in der Vergangenheit geändert, trägt die Datenhaltung diese Änderungen ebenfalls als Änderungsereignisse ein, prüft danach jedoch zusätzlich, ob sich diese Modifikationen auf die Gegenwart auswirken. Dies ist der Fall, wenn das Attribut der betroffenen Organisationseinheit zwischen dem Änderungszeitpunkt der Vergangenheit und dem Stand der Gegenwart nicht noch einmal modifiziert wurde. Die Änderung wird dann dementsprechend in den Relationen der Gegenwart umgesetzt.

Für die Suche wurde in der neuen Datenhaltung wieder eine Volltextindizierung integriert. Das heißt, dass Benutzer nach beliebigen Stichwörtern in allen Attributen suchen können. Die Volltextsuche kann in zukünftigen Versionen so erweitert werden, dass sie auch die Daten der Vergangenheit und Zukunft indiziert.

 

Neue und verbesserte Features in der Weboberfläche

Die Benutzeroberfläche von FAU.ORG hat ebenfalls einige Neuerungen zu bieten. So lassen sich beispielsweise Kontaktdaten, die Anschrift und die Statistikschlüssel rekursiv ändern. Das bedeutet, dass die Änderungen auch bei allen bzw. ausgewählten Kindern dieser Organisationseinheit umgesetzt werden. Das Verschieben von Einheiten ist nun auch problemlos möglich. Der Benutzer muss lediglich eine neue Organisationsnummer vergeben (dazu mehr weiter unten) und die Einheit wird mit allen Kindern im Baum an die entsprechende Stelle verschoben.

An der Benutzerfreundlichkeit der Weboberfläche wurde ebenfalls gearbeitet. Die Übersichtsseite einer Organisationseinheit enthält nun Sprungmarken, damit Benutzer schneller zur gewünschten Information gelangen. Des Weiteren unterstützt FAU.ORG nun die Anmeldung per SSO. Die wichtigsten Funktionen sind nun direkt aus dem Baum der Organisationseinheiten abrufbar. Des Weiteren zeigt der Baum nun die Langbezeichnung der Einheiten, was die Lesbarkeit verbessert.

Für die Integration der temporalen Semantik wurde in die Hauptseite eine Auswahlbox für das Systemdatum eingebaut. Hier wählt der Benutzer das Datum, in dem das System gerade betrieben wird. Damit entscheidet man also, ob man sich in der Vergangenheit, Gegenwart oder Zukunft arbeiten möchte. Die angezeigten Daten entsprechen dem zum ausgewählten Datum gültigen Stand der Organisationsstruktur. Das gewählte Systemdatum wird in allen Seiten in der kleinen Infobox auf der rechten Seite angezeigt.

Die verschiedenen Zustände (oder Versionen) der Organisationseinheiten lassen sich in der Historienansicht abrufen. Hier wird angezeigt, wer die Änderung erstellt hat, wann die Änderung erstellt wurde und zu welchem Zeitpunkt die Änderung gültig werden soll. Diese Ansicht lässt sich auf bestimmte Attributgruppen und Zeiträume filtern. Die Weboberfläche unterscheidet zudem seit der zweiten Version normale und kleine Änderungen. Eine kleine Änderung bezeichnet Modifikationen an den Daten, die lediglich Schreibfehler oder ähnliches betreffen und keine Wertänderung im eigentlichen Sinne darstellen. Kleine Änderungen lassen sich in der Historienansicht ausfiltern, was der Übersichtlichkeit beiträgt.

Das Erstellen von Brücken wird nun vollautomatisch von der Weboberfläche übernommen. Zur Erinnerung: jede Organisationseinheit besitzt eine Organisationsnummer aus fünf zweistelligen Zahlen. Der Organisationsbaum wird nach diesen Nummern aufgebaut und besitzt daher eine maximale Tiefe von fünf Ebenen. Ein Beispiel: der Hauptknoten des RRZE im Baum besitzt die Organisationsnummer 10 11 12 00 00. Dessen Vaterknoten hat dementsprechend die 10 11 00 00 00. Es kann nun vorkommen, dass ein Knoten einem Vaterknoten zugeordnet ist, der mehr als eine Ebene höher im Baum liegt. Mit anderen Worten überspringt ein Kind damit eine oder mehrere Ebenen. Der Datenmanagement-Lehrstuhl der Informatik besitzt beispielsweise die 15 13 00 16 00 und überspringt die dritte Ebene im Baum. Damit der Baum keine Lücken aufweist, existieren an diesen Stellen besondere Knoten, sogenannte Brücken (hier die 15 13 00 00 00), die als letzte definierte Stelle in der Organisationsnummer eine Doppelnull besitzen. Das Erstellen von Brücken wird in der zweiten Version nun vollkommen automatisch übernommen, sobald eine Brücke benötigt wird. Brücken werden ebenfalls automatisch gelöscht, falls sie keine Kinder mehr besitzt.

 

Zu den technischen Finessen werde ich im nächsten Blog-Artikel einen tieferen Einblick in die Umsetzung der Version 2 liefern.

RRZE ? Projects & Processes (P&P): An organisational structure in space and time

An organisational structure in space and time

The University Erlangen-Nuremberg’s central component for managing its organisational structure, FAU.ORG, has released its second version. There have been quite a few changes since the first version was originally released. Several improvements have been made to the user interface, improved features have been added and a new core component has been developed. This articles introduces the new, better, faster and easier-to-use FAU.ORG.

New Data management

FAU.ORG’s newly developed core component is now based on a relational database and offers the following:

  • Mapping the necessary information in a suitable entity relationship schema
  • Both persistance of data and changing the data (in separate relations)
  • Supporting temporal semantics for saving changes in the past, present and future.
  • full-text search in present data.

First, an entity relationship model (ER-model) was created from version 1’s data model with only a few changes. As most of the organisational units’ attributes only contain single values, a system with only few relations and a large number of attributes would have been possible. This would have impeded both the grouping of data belonging together, and a later implementation of access control for attribute groups. Use of several tables also allows use of a method called Lazy Loading. With this method, not all available data is loaded from data storage, but only the items the user needs at the moment. This saves memory and is more efficient in most cases.

In addition to saving the actual data, all changes in FAU.ORG are saved as change events in two tables. A change event is given when an attribute group is created, modified or deleted. Every change event contains a number of change entries with the old and new value of the modified attribute, date of the change and the date the change becomes active. This makes ?time travel? possible, as the state of every organisational unit at any point in time can be recreated from these change events.

To avoid having to create the state of an organisational unit with every access, the database contains the present state in the relations for data storage, as these can be read faster. If a user changes something in the future, change events are created and saved. A separate component reads these change events every night, selects those that become active the next day and includes them in the present state. That way, the tables are kept up to date. A similar component will later provision external systems with these changes. If organisational data is changed in the pats, data storage also enters these changes as change events, but then goes on to check if the modification affects the present state. That is the case if the attribute of the organisational unit in question is not modified again between the time of change in the past and the present state. Then, the change is included in the present relations.

For searching, the new data storage has been provided with a full-text index. That allows the user to search for keywords in all attributes. This can be expanded in future versions to allow indexing of past and future data.

New and improved features in the web interface

There are several improvements in FAU.ORG’s user interface as well. Recursive changing of contact data, mailing address and statistical keys is now possible, allowing changes for all or selected children of an organisational unit. Moving units is also much easier now. The user only needs to enter a new organisational number (more on this further down), and the unit and all its children are moved to a new place in the tree.

The website is now much more user-friendly. The starting page contains new jump labels, allowing users to get to the wanted information more easily. Furthermore, FAU.ORG now supports SSO login. The most important functions are available directly from organisational unit tree. The tree also uses the long description of units now, improving readability.

For better integration of the temporal semantic, the main page now features an entry box for the system date. Here, the user can chose the date at which the system runs. That way, you can chose whether to work in the past, present and future. The data displayed matches the organisational structure valid at the selected date. The system data chosen is always displayed in an info box on the right side of the screen.

The organisational units’ different states (or versions) can be selected in the history view. Here you can see who entered a change, and at what time that change will become active. Filters for attribute groups and time periods can be used in this view. The web interface also differenciates between normal and small changes. A small change indicates minor modifications to data like fixed spelling mistakes. They do not normally represent real changes to the values themselves. These small changes can be filtered out in the history view.

Bridges are now created automatically by the web interface. A reminder: Every organisational unit has its own organisational number, consisting of five two-digit numbers. The organisational tree is created from these numbers and accordingly has a maximum depth of five levels. E.g.: The RRZE’s main node in the tree is organisational number 10 11 12 00 00. Its father node is therefore 10 11 00 00 00. It is possible, however, for nodes to be attached to a father node that is more than one level higher up the tree. In other words, the child jumps one or more levels. Since the tree cannot have any ?gaps? special nodes, so called bridges, are entered in these places. Their last defined digit ist 00 (in our example 15 13 00 00 00). These bridges are now created automatically when they are needed. They are also deleted automatically if they do not have any children.

For the finer technical details, I will use the next blog article to give some insight into version 2’s implementation.

Neues von FAU.ORG

Alles neu macht der Mai!

Hallo, mein Name ist Martin Fischer und ich bin seit dem 1. Mai 2009 beim Regionalen RechenZentrum als Entwickler für das FAU.ORG Projekt angestellt. Die Einarbeitungsphase gestaltete sich recht unkompliziert, da sich Krasimir Zhelev netterweise genügend Zeit nahm, mich in die Architektur und die Sourcecodestruktur einzuarbeiten. Der größte Teil der Einarbeitung machte daher die Installation der benötigten Eclipse-Plugins und der initiale Datenimport, um lokal mit FAU.ORG entwickeln und testen zu können. Mittlerweile ist fast ein Monat vergangen und habe ich mir die Verzeichnisstrukturen verinnerlicht und kann mich auf die eigentlichen Aufgaben konzentrieren.

Ausblick auf Release 2

Nachdem am 24. März die erste Version von FAU.ORG online ging, ist nun das zweite Release in Planung.

Neue Funktionen

In der zweiten Version von FAU.ORG soll es möglich sein, den Baum, der die Organisationsstruktur repräsentiert, zu einem bestimmten Zeitpunkt in der Vergangenheit zu betrachten. Dies betrifft sowohl die Attribute einer Organisationseinheit, als auch die Struktur des Baumes.

Historie

Als Persistierungsschicht wurde mit Jackrabbit ein Java Content Repository verwendet, damit die Datenhaltung versioniert werden kann. Ändern sich Attribute von Organisationseinheiten oder die Struktur des Baumes, wird für jede Änderung eine Version angelegt, die später wieder abgerufen werden kann. Der Benutzer wählt hierzu ein Datum und lässt sich den Baum mit dem Stand zum gewählten Zeitpunkt anzeigen.

Rekursives Ändern von Attributen

Zur Vereinfachung von Änderungsoperationen an Attributen von Organisationeinheiten wird das neue FAU.ORG in der Lage sein, Veränderungen an Attributen von Einheiten rekursiv durch alle Untereinheiten zu propagieren. Damit können Benutzer beispielsweise die Adresse eines Instituts ändern und die Adressen aller untergeordneter Lehrstühle, etc. werden automatisch mitgeändert – versioniert selbstverständlich.

Verschieben oder was der Benutzer dafür hält

Das zweite Release von FAU.ORG soll weiterhin die Möglichkeit enthalten, Organisationseinheiten im Baum zu verschieben. Davon sind natürlich auch alle untergliederten Einheiten der zu verschiebenden betroffen. Der Benutzer wählt lediglich den Knoten aus, der zukünftig als Übergeordnete Einheit fungieren soll und der Teilbaum wird automatisch verschoben. Dabei werden die Organisationsnummern automatisch angepasst.
Im Detail betrachtet ist die Bezeichnung Verschieben jedoch ein wenig irreführend, da eine neue Organisationseinheit angelegt und die alte invalidiert wird. Der Benutzer wählt daher neben dem neuen übergeordneten Knoten auch ein Auslaufdatum für die alte Struktur und ein Einführungsdatum der neuen. Zusätzlich wird ein Datum angegeben, mit dem die alte Einheit ein neues Publikationskennzeichen bekommt. Abschließend wird dem Benutzer eine Liste von Attributen angezeigt, die nach dem Verschieben der Einheit einer Aktualisierung bedürfen. Die Anpassung dieser Attribute kann selbstverständlich rekursiv erfolgen.

Sonstiges

Des Weiteren ist vorgesehen Übersetungen in verschiedene Sprachen besser in das Datenmodell zu integrieren, so dass die gesamte Beschreibung einer Organisationseinheit in unterschiedlichen Sprachen vorliegen kann.

Überdies sind noch kleinere Änderungen geplant, wie zum Beispiel das Breadcrumb-Menu anklickbar zu machen, um Benutzern die Navigation zu vereinfachen.

News from FAU.ORG

The merry month of May!

Hello, I’m Martin Fischer. I was hired as developer for the RRZE’s project FAU.ORG on May 1st 2009. It didn’t take me long to adjust to my new job, since Krasimir Zhelev was kind enough to take the time and introduce me to both architecture and source code structure. Therefore, the biggest adjustment for me was installing the needed Eclipse-Plugins and importing the necessary data to enable me to develop and test FAU.ORG locally. After almost a month, I have now internalised the directory structure and am able to start with the work I was hired for.

Outlook on Release 2

After the first version of FAU.ORG went live on March 24th, the second release is now in design.

New Functionality

FAU.ORG’s second version should offer a view of the organisational tree at points in the past. This includes both attributes of organisational units and the tree’s structure.

History

For use as a persistent layer, we chose to use Jackrabbit as Java Content Repository, to put data storage under version control. As soon as changes to organisational units’ attributes or the tree’s structure occur, every change is saved in a separate version that can be recalled later. The user choses a date, and can view the tree with all attributes that were valid at that time.

Recursive changing of attributes

For easier changes to the attributes of organisational units, the new FAU.ORG will be able to propagate unit attribute changes recursively for all subunits. That allows users to change the adress of an institute, automatically changing all chairs, etc. within the institute as well – versioned, of course.

Moving units – or seeming to

FAU.ORG’s second release should also contain a way to move organisational units within the tree. This affects all subdivisions of that unit, too, of course. The user simply choses the node representing the future superordinate unit, and the relevant part of the tree will be moved, adjusting all organisational numbers as necessary.
Viewed in detail, “moving” is slightly misleading, as a new organisational unit is created and the old one is deleted. Therefore, the user choses a expiration date for the old structure and an introduction date for the new one. A third date is needed, stating when the old unit receives a new sign for publications. Finally, the user is given a list of attributes that need to be brought up to date after the move. These can be adjusted recursively, of course.

Miscellaneous

Translations for different languages will be better integrated into the data modell, making the whole description of an organisational unit available in different languages.

Furthermore, smaller changes are planned, like making the breadcrumb menu clickable for easier navigation.