Donnerstag, 21. Februar 2013

Mit Emacs Make dort starten, wo Makefiles liegen

Java Programmierer neigen zu exzessiv sinnlosem inflationärem Gebrauch von Unterverzeichnissen. Es gehört zum guten Ton, dass man sich erst mal durch einen Dschungel an Unterverzeichnissen hangeln muss, bevor man die erste Zeile Code schreiben darf. Sun hat es ehemals den Grundstein für diese Unart gelegt, indem man gezwungen war jedes Package in ein eigenes Verzeichnis legen zu müssen. Das entwickelte sich zum Fluch als man auf die Idee kam, sämtliche Klassennamen mit Domänennamen zu prefixen. Und die Maven-Verwirrten haben sich jetzt zum Ziel gesetzt, den Vogel endgültig abzuschießen. Man achte auf die Struktur eines simplen Hello-World-Programms:

my-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- com
    |           `-- mycompany
    |               `-- app
    |                   `-- App.java
    `-- test
        `-- java
            `-- com
                `-- mycompany
                    `-- app
                        `-- AppTest.java

Das sind sage und schreibe 12 Verzeichnisse für 3 Dateien. Ich denke die nächste Major-Version von Maven sollte sich gemäß Moorschem Gesetz auf wenigsten 24 Verzeichnisse steigern. Getreu dem Maven-Leitspruch: Ceterum censeo inodes esse delendam.

Emacs-Benutzer, die mit dieser Anti-Information gequält werden, haben beim Entziffern der Kaiserlichen Botschaft in den Tiefen des Gesetzes das Problem, dass der Build-Vorgang nicht an der Stelle gestartet werden kann, an der die Datei liegt, die gerade editiert wird. Das zum Quellcode zugehörige Makefile oder vergleichbarer Pom-Schrott liegt typischerweise 12 bis 96 Verzeichnisse höher.

Die Lösung ist wie so oft im EmacsWiki zu finden. Dort kann man sich die Funktion upward-find-file klauen, die nach einer passenden Datei im gesamten Verzeichnisbaum sucht:

(defun upward-find-file (filename &optional startdir)
  "Move up directories until we find a certain filename. If we
  manage to find it, return the containing directory. Else if we
  get to the toplevel directory and still can't find it, return
  nil. Start at startdir or . if startdir not given"

  (let ((dirname (expand-file-name
    (if startdir startdir ".")))
 (found nil) ; found is set as a flag to leave loop if we find it
 (top nil))  ; top is set when we get
      ; to / so that we only check it once

    ; While we've neither been at the top last time nor have we found
    ; the file.
    (while (not (or found top))
      ; If we're at / set top flag.
      (if (string= (expand-file-name dirname) "/")
   (setq top t))
      
      ; Check for the file
      (if (file-exists-p (expand-file-name filename dirname))
   (setq found t)
 ; If not, move up a directory
 (setq dirname (expand-file-name ".." dirname))))
    ; return statement
    (if found (concat dirname "/") nil)))

Damit kann ein Wrapper der Compile-Funktion relativ einfach folgendermaßen definiert werden:

(defun compile-next-makefile ()
  ""
  (interactive)
  (let ((default-directory (or (upward-find-file "Makefile") ".")))
    (command-execute 'compile)))

Ich definiere mir dafür typischerweise das folgende Tastaturkürzel.

(global-set-key (kbd "C-c m") 'compile-next-makefile)

PS: Der Begriff Anti-Information ist übrigens nicht auf meinen Mist gewachsen. Den hat sich Max Landorff in "Der Regler" ausgedacht. Ich finde ihn recht passend für vieles was einem im Java-Umfeld über den Weg läuft.

Donnerstag, 14. Februar 2013

OpenLDAP Quickstart

Die Version 2.4 von OpenLDAP ist mit der Sense durch die bisherige Art das Programm zu konfigurieren gegangen. Während früher die Konfigurationsoptionen in der Datei slapd.conf lagen, liegen sie nun im Directory selber. Alle Änderungen gehen nur noch über eine LDIF-Datei, die ldapadd oder ldapmodify vorgeworfen wird. Das setzt voraus, dass der Slapd läuft. Wenn man Slapd derart verkonfiguriert, dass er nicht mehr startet, kann die fehlerhafte Konfiguration auch nicht mehr berichtigen. Es sei denn man editiert die internen cn=config-Dateien von Slapd, was man aber auf keinen Fall tun soll. Über Vor- und Nachteile dieses Ei-Huhn-Problems kann man streiten. Was aber wirklich albern ist, ist der Sachverhalt, dass die OpenLDAP-Quick-Start-Anleitung von der Konfigurationsumstellung leider noch nichts mitbekommen hat. Wenn es schnell gehen soll, ist also der alte Weg doch besser.

Wenn man der neuen reinen Lehre folgen möchte wird es komplizierter. Die folgenden Ausführungen beziehen sich auf eine Default-Installation des "openldap-servers"-Pakets eines Red Hat Enterprise Linux Servers in der Version 6.3.

Zuerst muss man die Nummer der Konfigurationsdatei finden, die Bestandteil des DN der Konfigurationsoptionen ist. Die Datei ist nämlich bereits durch die Paket-Installation angelegt worden.

# grep -l olcSuffix /etc/openldap/slapd.d/cn\=config/*
/etc/openldap/slapd.d/cn=config/cn=schema.ldif
/etc/openldap/slapd.d/cn=config/olcDatabase={2}bdb.ldif

In diesem Fall ist es '{2}bdb'. Mit Hilfe dieses Strings können nun die drei Werte gesetzt werden, die man minimaler Weise für einen Slapd setzten muss:

  • Base DN (olcSuffix)
  • Admin DN (olcRootDN)
  • Admin Passwort (olcRootPW)
Die entsprechende LDIF-Datei sieht folgendermaßen aus:

dn: olcDatabase={2}bdb,cn=config
changeType: modify
replace: olcSuffix
olcSuffix: 0=my-base

dn: olcDatabase={2}bdb,cn=config
changeType: modify
replace: olcRootDN
olcRootDN: cn=my-admin,o=my-base

dn: olcDatabase={2}bdb,cn=config
changeType: modify
replace: olcRootPW
olcRootPW: {SSHA}TAXHVcISg/XoRXTe2fSJFYpZTWYqix0t

Das Passwort erzeugt slappasswd:

# slappasswd
New password:
Re-enter new password:
{SSHA}TAXHVcISg/XoRXTe2fSJFYpZTWYqix0t

Die Datei wird mit ldapadd importiert:

# ldapadd -Y EXTERNAL -H ldapi:/// -f conf.ldif

Anschließend kann geprüft werden, ob die Anmeldung funktioniert, indem man sich mit dem Admin-Konto anmeldet:

# ldapsearch -x -D 'cn=my-admin,o=my-base' -W '(objectclass=*)'
Die Suche wird zwar kein Ergebnis liefern, weil im LDAP noch nichts enthalten ist, aber die Anmeldung mit dem neuen Passwort wird geprüft. Um sich mit JXplorer oder einem anderen Browser anzumelden, muss noch der Wurzelknoten definiert werden:
dn: o=my-base
objectclass: top
objectclass: organization
o: my-base
Der Import mit Hilfe des Manager-Kontos:
# ldapadd -x -D "cn=my-admin,o=my-base" -W -f top.ldif

Freitag, 1. Februar 2013

Netzwerkverschlüsselung für Oracle aktivieren

Oracle ist in der Lage die Netzwerkkommunikation auch ohne SSL und Zertifikate zu verschlüsseln. Dabei wird der Payload der TCP 1521-Verbindung verschlüsselt. Der Listener bekommt davon gar nichts mit und braucht auch nicht umkonfiguriert werden. Allerdings wird auf Client-Seite eine aktuelle Version des JDBC-Treibers benötigt. Das ojdbc14.jar funktioniert nicht. Man kann die Option mit dem Oracle Net Manager aktivieren:
Wichtig ist, dass der Encryption-Type auf "required" steht, da sonst auch unverschlüsselte Verbindungen zugelassen werden. Die Konfiguration steht anschließende in der sqlnet.ora-Datei:
SQLNET.ENCRYPTION_TYPES_SERVER= (AES256)
SQLNET.ENCRYPTION_SERVER = required

Sonntag, 13. Januar 2013

NODEADKEYS mal anders

Früher war alles einfach. Man nahm die X11-Konfigurationsdatei und aktivierte die Option. Heutzutage ist es ... eigentlich immer noch einfach. Man muss nur wissen wie es geht. Nur leider findet man es bekannter maßen mit dem Alter immer lästiger, sich neue Wege für alte Ziele zu merken. Deswegen steht es hier. In /etc/default/keyboard die folgende Zeile eintragen:
XKBVARIANT="nodeadkeys"
Und danach den folgenden Befehl aufrufen:
udevadm trigger --subsystem-match=input --action=change
Steht alles in der keyboard man page. Aber das ist schon wieder so einfach, dass man nicht darauf kommt.

Freitag, 4. Januar 2013

Nach Unterstrich suchen in SQL

SQL bietet das Schlüsselwort LIKE, um Textvergleiche durchführen zu können. Die Syntax ist aber für alle, die reguläre Ausdrücke gewohnt sind, sehr gewöhnungsbedürftig. Eine beliebig lange Zeichenkette wird durch den regulären Ausdruck '.*' abgedeckt. Die Entsprechung in SQL ist das Prozentzeichen '%'. Will man nur ein einzelnes Zeichen abdecken reicht im regulären Ausdruck der Punkt '.' während man in SQL den Unterstrich '_' verwenden muss. Richtig lästig wird es aber erst beim Quoten. Typischerweise stellt sich das Problem bei regulären Ausdrücken für DNS-Namen und URLs. Der richtige reguläre Ausdruck für alle com-Domänen ist also '.*\.com'. Für jeden, der mal was C-ähnliches gelernt hat, a priori klar. Nicht so in SQL, da man in SQL mit dem Schlüsselwort ESCAPE für jeden String das passende Escape-Zeichen definieren muss. Das ist zwar flexibel aber umständlich wie man an dem folgenden Beispiel sieht, dass nach allen englischsprachigen Lokalisierungsbezeichnern sucht.
sqlite> create table locale (l10n text);
sqlite> insert into locale values ('en_US');
sqlite> select l10n from locale where l10n like 'en\_%' escape '\';
en_US

Doppelte finden mit "group by" und "having" in SQL

Das folgende Snipplet zeigt eine Art wie man doppelte in SQL finden kann:
select email, count(email) as dup
from person
group by email
having (dup > 1)

Mittwoch, 19. Dezember 2012

Random (type 4) Universally Unique IDentifier in Oracle

Oracle provides a function called sys_guid() to generate unique identifier. But this function produces different results on different systems. It is explained here. The following custom function generates a 16 byte RAW variable containing a random UUID. This is a type 4 UUID according to RFC 4122.
CREATE OR REPLACE FUNCTION random_uuid RETURN RAW IS
  v_uuid RAW(16);
BEGIN
  v_uuid := sys.dbms_crypto.randombytes(16);
  RETURN (utl_raw.overlay(utl_raw.bit_or(utl_raw.bit_and(utl_raw.substr(v_uuid, 7, 1), '0F'), '40'), v_uuid, 7));
END random_uuid;
The function uses the package dbms_crypto to generate 16 random bytes and sets the high nibble of the 7th byte (starting with 1) to 0100b (see 4.1.3. in RFC 4122). This is done with the binary functions from the utl_raw package. It might be necessary to grant the execute permission for the dbms_crypto package:
grant execute on sys.dbms_crypto to random_uuid_user;
This is a result of a StackExchange question.