Dienstag, 3. Dezember 2013

Reading Manifest attributes from a JAR

In C it was common practice to define a program version number in a file called VERSION. In the Make file there was a line which reads the file and stores its in a variable.
VERSION=$(shell cat VERSION)
And later on it was possible to use the variable as a definition argument for the C compiler:
program.o: program.c
	$(CC) -DVERSION=$(VERSION) -o $@
In the code it was possible to craft a version message by the use of this definition.
fprintf (stderr, "program version %s\n", VERSION);

In Java things are much more complicated. It is common practice in Java to store the version number of a program not in the code of the program itself but in the Manifest file of the JAR, which contains the program. The correct manifest attribute is call Implementation-Version. But there is no simple way to reference the Manifest attributes in a program. Instead it is necessary to calculate a resource URL for the Manifest file based on a class, which is in the same JAR. This URL can be opened as a stream and this stream can be used to parse the contents of the Manifest. The following example shows the class ManifestAttributes, which does this.

class manifest
{
  static int n = 0;
  static void debug (Object message)
  {
    System.err.println ("#" + n + "# " + message);
    n = n + 1;
  }

  public static class ManifestAttributes
  {
    private java.util.jar.Attributes attributes;

    public ManifestAttributes ()
    {
      Class this_class = ManifestAttributes.class;
      String class_name = this_class.getName();
      String class_path = class_name.replace (".", "/") + ".class";
      String class_url = this_class.getResource(class_path).toString();
      String manifest_url = class_url.replace (class_path,
                                               "META-INF/MANIFEST.MF");
      java.io.InputStream stream = null;
      java.util.jar.Manifest manifest;
      try {
        stream = new java.net.URL(manifest_url).openStream();
        manifest = new java.util.jar.Manifest(stream);
      }
      catch (java.io.IOException exception) {
        throw new RuntimeException (exception);
      }
      finally {
        try {
          if (stream != null) stream.close();
        }
        catch (java.io.IOException exception) {
          throw new RuntimeException (exception);
        }
      }
      attributes = manifest.getMainAttributes();
    }

    public String get (String key)
    {
      return attributes.getValue(key);
    }
  }

  public static void main (String[] args)
  {
    ManifestAttributes attributes = new ManifestAttributes();
    debug (attributes.get("Manifest-Version"));
    debug (attributes.get("x"));
  }
}

// Local Variables:
// compile-command: "javac manifest.java && jar cvfe manifest.jar manifest manifest*.class && java -jar manifest.jar"
// End:

Donnerstag, 28. November 2013

Reading Subversion information in scripts

Sometimes it is useful to know something about a Subversion repository. The "svn diff" command for example works only with URLs. If you have to write a wrapper for "svn diff" to perform some standard tasks it is necessary to get the repository URL for a directory. This is possible with the "svn info" command. Some people propose to use grep and sed to parse the output of "svn info". But parsing with grep and sed is often not very reliable, because they search only for string patterns. This makes it for example hard to distinguish a revision number of a commit from a revision number of a entry, because they share the same label.

But Subversion provides a far better option, which makes parsing much easier. The "svn info" command can generate XML output, which can be parsed with "xmllint" and an appropriate XPath expression to get the exact information. The following Bash script is a small wrapper around "svn info --xml" and "xmllint --xpath".

#! /bin/bash
if [ "$2" ] ; then
    TARGET=$1
    shift
else
    TARGET=.
fi
svn info --xml "$TARGET" | 
if [ "$1" ] ; then
    if [ '@' = $(cut -c 1 <<<$(basename "$1")) ] ; then
        xmllint --xpath 'string('"$1"')' -
    else
        xmllint --xpath "$1"'/text()' -
    fi
    echo
else
    xmllint --format -
fi

The script makes it quite easy to get the right information:

trunk$ svninfo /info/entry/@revision
2647
trunk$ svninfo /info/entry/commit/@revision
2646
Running the script without any argument pretty prints the raw XML date. This is useful to write the exact XPath expression.

Freitag, 22. November 2013

Defining macros in Ant to read files

Ant is a scary build tool to compile Java code. It aims to be a better Make but it is just a sludge of everything without doing anything right. It implements a programming language with XML syntax, which is simply pain to write. But sometimes you have to use it, because Sun failed to design something better, when they designed Java.

Make files typically read some values or lists from other files. Because Make does not try to be a Shell like Ant, the Shell is used for this:

version = $(shell cat VERSION)
This reads the contents of the file "VERSION" into the variable "version". Although Ant tries to be a Shell it has no build-in function to do the same. Instead it provides you a way to define macros in XML syntax, to define a function. The following code defines an Ant function, which reads the contents of a file into a property without any new lines.
<macrodef name="loadfilevalue">
  <attribute name="property"/>
  <attribute name="file"/>
  <sequential>
    <loadfile property="@{property}" srcFile="@{file}">
      <filterchain><striplinebreaks/></filterchain>
    </loadfile>
  </sequential>
</macrodef>
With this macro it is possible to read the "VERSION" file:
<loadfilevalue property="version" file="VERSION"/>
Something similar can be done for lists of values. Ant provides a way to modify the contents of a file with regular expressions while reading it. This makes it possible to write a macro, which reads some lines from a file into a coma delimited property, which is usually required as the input to specify a list of files in Ant. This is the macro.
<macrodef name="loadfilelist">
  <attribute name="property"/>
  <attribute name="file"/>
  <sequential>
    <loadfile property="@{property}" srcFile="@{file}">
      <filterchain>
        <tokenfilter>
          <replaceregex pattern="$" replace=","/>
        </tokenfilter>
        <striplinebreaks/>
        <tokenfilter>
          <replaceregex pattern=",$" replace=""/>
        </tokenfilter>
      </filterchain>
    </loadfile>
  </sequential>
</macrodef>
And this shows how to use it.
<loadfilelist property="files" file="FILES"/>

Donnerstag, 14. November 2013

Create classpath while compiling Java with GNU Make

Compiling Java files with GNU Make can be a bit tricky. The problem is, that a class path in the command line must be specified with colons while a class path specified in a manifest file has to be specified with spaces. This makes it necessary to convert either colons to spaces or spaces to colons. The following shows how to convert spaces to colons.

The main problem is that is quite hard the specify a single space in a GNU Make file. This requires the following trick. First you have to define a variable with nothing in and after that you can define a space by delimiting it with the variable for nothing. After that you have a variable with a single space. The following part of a Make file shows how the class path conversion can be done with the previously defined space.

# Compile Java source
e :=
space := $(e) $(e)
$(CLASSES): $(BUILD)/%.class: src/%.java | $(BUILD)
	@$(ECHO) JAVAC: $@
	@$(JAVAC) -Xlint:unchecked \
		-cp .:$(subst $(space),:,$(addprefix jar/,$(LIBS))) \
		-sourcepath src:$(subst $(space),:,$(addprefix jar/,$(SRCS))) \
		-d $(BUILD) $(JFLAGS) $< \
		|| { $(RM) $@ && $(EXIT) 1 ; }

GNU Make wrapper for Ant.

The following is a GNU make wrapper for Apache Ant. Those targets, which must be implemented in GNU Make can be implemented in the Make file and all other targets are passed to Ant. And it is possible to mix different Ant and Make targets.
all:
 @ant -e jar

# The following prevents the execution of "cat" on systems, which do not
# support it.
_import:
 $(eval PACKAGE := $(shell cat PACKAGE))
 $(eval VERSION := $(shell cat VERSION))

DEVELOPMENT := 
PRODUCTION := 
BIN_JAR = build/jar/$(PACKAGE)-$(VERSION).jar

install: _import binjar
 scp $(BIN_JAR) $(PRODUCTION)/.
 cp $(BIN_JAR) $(DEVELOPMENT)/.

tag: _import
 $(eval TRUNC_URL := $(shell svn info --xml | xmllint --xpath '/info/entry/url/text()' -))
 svn -m "TAG: $(VERSION)" cp $(TRUNC_URL) $(subst trunk,tags/$(VERSION),$(TRUNC_URL))

# Pass all other targets to ant
%:
 @ant -e "$@"
In this case the Subversion tagging is not done in Ant. It is easier to do it in the Make file.

Mittwoch, 9. Oktober 2013

Checked Exceptions vs Interfaces

So genannte "Checked Exceptions" sind Ausnahmen in Java, die auf jeden Fall vom Programmierer behandelt werden müssen. Tut er das nicht, wirft der Compiler einen Fehler und verweigert die Übersetzung. Am Konzept der Checked Exceptions gibt es reichlich Kritikpunkte. Java selbst versucht in dem entsprechenden Tutorial das Konzept zu verteidigen. Besonders pikant ist aber, dass das Konzept der Checked Exceptions in Widerspruch steht zu einem anderen Konzept von Java und zwar den "Interfaces". Bei einem Interface handelt es sich um eine abstrakte Spezifikation eines Verhaltens, das unabhängig von der Art der Implementation ist. Das Interface weiß also nichts darüber, wie es implementiert sein könnte. Somit kann das Interface auch nicht wissen, ob bei einer Implementation eine Ausnahme auftreten kann und wenn ja welche. Das wiederum bedeutet, dass ein Interface gar keine Ausnahmebehandlung vorsehen kann, da dem Interface gar nicht klar sein kann, welche Fehler bei der jeweiligen Implementation auftreten könnten.

Java definiert seit der Version 1.5 das Interface "Appendable". Dieses Interface spezifiziert den Vorgang des Anhängens einer Zeichenkette an ein Objekt mittels der Methode append. Merkwürdigerweise sind alle drei Varianten von append so definiert, dass sie eine IOException werfen können. Das wirft die Frage auf, woher das Interface weiß, dass bei seiner Implementation eine IOException auftreten kann, obwohl der Sinn eines Interfaces darin besteht, dies gar nicht wissen zu dürfen? Die Antwort liegt in der hellseherischen Fähigkeit dieses Interface. Bei der Definition des Interfaces ging man davon aus, dass es mal eine Implementation geben könne, die beim Vorgang des Anhängens eine IO-Operation ausführen müsste. Und genau das würde das Entstehen einer IOException ermöglichen. Wenn man also vom Konzept der Checked Exceptions nicht abrücken will, muss man das Interface so gestalten, dass alle theoretisch denkbaren Checked Exceptions vorhergesehen werden um sie im Interface definieren zu können. Ein derartiges Anliegen ist natürlich völliger Unsinn.

Ergebnis dieses konzeptionellen Widerspruchs ist, dass man das Interface Appendable mit eigenen Checked Exceptions, die die Designer von Java leider nicht vorhergesehen haben, gar nicht implementieren kann. Das wiederum bedeutet, dass man in einer Implementation von Appendable alle Checked Exceptions in Unchecked Exceptions umwandeln muss. Und das wirf dann die Frage auf: wozu das eigentlich? Insbesondere wenn man sich vor Augen führt, dass Appendable kein Einzelfall ist. Das Problem tritt in gleicher Weise beim Iterator auf. Und obwohl der Iterator schon seit Version 1.2 mit an Bord ist, war man damals immerhin so schlau, sich die Blöße mit der IOException gar nicht erst zu geben. Das Iterator-Interface definiert keine implementationsspezifischen Ausnahmen, obwohl natürlich sonnenklar ist, dass auch beim Iterieren IOExceptions auftreten können.

Am Ende stellt sich dann die Frage: auf was will man lieber verzichten: Interfaces oder Checked Exceptions? Ich für meinen Teil bin der Meinung, wer Checked Exceptions benutzt ist selber Schuld.

Dienstag, 8. Oktober 2013

Java inherits Common Lisp´s name spaces

Java puts classes and variables in different name spaces. This is a bit like Common Lisp where functions have also their own name space. Common Lisp has been criticized for this and has been called ugly. Oracle´s Java 1.7 does it the same and compiles the following example without any complain:
class names
{
  public static void main (String[] args)
  {
    names names = new names();
  }
}

Freitag, 16. August 2013

Startpage als Standard-Suchmaschine in älterem Firefox

Unser aller Held Edward Snowden hat uns nahe gelegt, deutlich mehr Augenmerk auf Datenschutz und Datensicherheit zu legen. Für mich fängt das mit der Google-Suche an. Glücklicherweise gibt es einen Anbieter namens ixquick, der die Google-Suche anonymisiert und unter dem Namen Startpage anbietet. Um die Suchmaschine im Browser zu nutzen gibt es für Firefox eine Search-Engine-Definition.

Beruflich bin ich aber gezwungen eine ältere Firefox-Version zu nutzen. Die hat das Problem, dass die Suche über die URL-Eingabe unabhängig von der Suche über das Sucheingabefeld konfiguriert wird. Die Lösung für das Problem findet sich in der Knowledgebase von Startpage. Man muss lediglich auf der about:config-Seite die Option keyword.URL parametrisieren.

Trägt man dort den folgenden Wert ein, klappt die Suche auch über die URL-Zeile:

https://startpage.com/do/search?language=german&cat=web&query=

Samstag, 20. Juli 2013

Android's Package Download

Recently I have asked on several forums (XDA Developer, Stackexchange) how the Android package download works. I got no useful answer. First the bone heads at Android Enthusiasts did not understand my questions and after they got it, they closed the questions, because the topic has nothing to do with Android (roflpimp). At XDA Developer I was not able to ask the question in the right section, because I had not written enough junk to be qualified for the right sections.

You see I had to figure it out on myself. I configured an ALIX board as an wireless access point connected my old Cyanogen 7 Defy and started an update. I captured the traffic with Tshark and analyzed it with Wireshark.

The Android 2 client does two requests for a package update. The first request gets answered by an redirect and the second starts the download. This is the first request.

And this is the second.

First the client contacts the host android.clients.google.com and requests something from /market/download/ and after that the client contacts some random host in a probably random sub domain below android.clients.google.com and requests something from /market/GetBinary/. The traffic is not encrypted. This makes to possible to block the package download without breaking other Google services.

This is an example configuration for Squid.

acl apps url_regex "/etc/squid3/apps.url"
http_access deny apps
deny_info TCP_RESET apps

The file with the regular expression contains only one entry.

android\.clients\.google\.com/market/(download|GetBinary)/

Successful blocks are marked as TCP_DENIED in the log file.

1374352802.189      0 192.168.3.27 TCP_DENIED/403 0 GET http://android.clients.google.com/market/download/Download? - NONE/- text/html

Donnerstag, 11. Juli 2013

Renaming inheritance relations with Rhino in Oracle´s SQL Data Modeler

The default naming rule for inheritance relations is a simple enumeration.

  • Hierarchy_1
  • Hierarchy_2
  • and so on...

Recently I had the problem to clean up an existing model. This can be done by hand but it is a very annoying job. Oracle´s SQL Data Modeler includes Mozillas Rhino engine to perform automatic tasks on the model. It is much more convenient to unify the relation names by a script. The following script does the job.

var entities = model.getEntitySet().toArray();
for (var e = 0; e < entities.length; e++) {
    var entity = entities[e];
    if (entity.isInheriting()) {
        var relation = entity.getInheritanceRelation();
        var source = relation.getSourceEntity().getName();
        var target = relation.getTargetEntity().getName();
        relation.setName(source + "_" + target + "_ih");
        relation.setDirty(true);
    }
}

The new names are created by the name of the source entity and the name of the target entity separated by an underline and suffixed by "ih".

The documentation of the classes and methods available from JavaScript is quite limited. But the file datamodeler/xmlmetadata/doc/index.html in the Data Modeler package list all of them and it is possible to use the debugger repl to test their functionality.

Mittwoch, 10. Juli 2013

Abuse inheritance for embedding with SQL Developer

Creating relational models in SQL is often a very annoying job, because of the limited expressiveness of the relational model. Thanks to PostgreSQL it is possible to create inheritance relationships between different entities. But the object oriented world spurns more and more inheritance. Inheritance was invented to reuse code but after Barbara Liskov formulated her substitution principle most object oriented disciples bless embedding instead of inheritance. Evangelists like Google´s Go banish inheritance at all and allow only embedding.

Never the less Oracle´s SQL Developer does not know anything about embedding and provides only single inheritance. The following example shows how to use this for embedding. I would like to created objects in my database which timestamps. A "creatable" should have a create time stamp, a "deletable" should have an additional delete time stamp and a "modifyable" should add a third time stamp. This is the logical model:

The engineering strategy "one table per child" results in a relational model with only one table.

The attributes of all ancestors are merged into the table. Whenever I need the three time stamps I can specify the inheritance without the need to add them manually to the entity.

But one thing is still annoying. The columns are prefixed with the abstract table names, which leads to unnecessary redundancy in the name of the columns. I did not find a way to suppress this naming style but I found a way to fix the names by writing a custom transformation script. SQL Developer embeds Mozilla´s Rhino engine, which provides a way to manipulate the engineered model. The following script removes the table prefixes from the three columns.

function set_name (object, name)
{
    object.setName(name);
    object.setDirty(true);
}

tables = model.getTableSet().toArray();
for (var t = 0; t<tables.length;t++) {
    table = tables[t];
    tname = table.getName();
    columns = table.getElements();
    for (var c = 0; c < columns.length; c++) {
        column = columns[c];
        cname = column.getName();
        if (m = cname.match(/.+_((CREATE|DELETE|MODIFY)_TS)$/))
            set_name(column, m[1]);
    }
}

Freitag, 5. Juli 2013

instanceof in Java

Javas instanceof Operator ist nicht nur wahr für die Klasse der ein Objekt angehört sondern auch für sämtliche Elternklassen. Das folgende Beispiel
class instance
{
  static class A {}
  static class B extends A {}

  static<T> void println(T arg) { System.out.println(arg); }

  public static void main (String[] args)
  {
    A a = new A();
    B b = new B();
    A c = b;

    println (a instanceof A);
    println (a instanceof B);
    println (b instanceof A);
    println (b instanceof B);
    println (c instanceof A);
    println (c instanceof B);
  }
}
generiert die folgende Ausgabe:
$ javac -cp . -Xlint:unchecked instance.java && java instance
true
false
true
true
true
true
Lediglich Objekte der Elternklasse sind keine Instanz einer Kindklasse.

Dienstag, 5. März 2013

Doing the same but beeing inefficient

Sometimes it seems that this is the maxim of a typical Java developer. Take a look at two ways to build a Java program.

This is the old fashioned legacy way a developer would build something, he will write a Makefile. And it might look like this:

all jar: xmuta.jar

clean:
        -rm *.class xmuta.jar *~

compile: xmuta.class

xmuta.jar: manifest xmuta.class
        jar cvfm $@ $< *.class

xmuta.class: xmuta.java
        javac $<

The Makefile contains the rules for compilation and packaging. It takes 167 characters to write everything down.

Now take a look at the new style by writing an XML file (oh God how modern). Okay somebody might argue, that Ant is already old fashioned but there is one thing sure in this world: with Maven it gets even worse. So I consider only Ant:

<project>
  <target name="clean">
    <delete>
      <fileset dir="." includes="*.class"/>
      <fileset dir="." file="xmuta.class"/>
      <fileset dir="." includes="*~"/>
    </delete>
  </target>
  <target name="compile">
    <javac srcdir="." destdir="." debug="true"/>
  </target>
  <target name="jar" depends="compile">
    <jar destfile="xmuta.jar" basedir="." 
         manifest="manifest" includes="*.class"/>
  </target>
</project>

And what does "wc -c"say? 443 characters. I do not know whether taking 443 characters is much more secure but it is definitely more than twice of the code the old fashioned guy has to write down. So people who like to hear themselves should write build files instead of make files.

But how about the time you have to spend for compilation? Be warned: if you have a sensitive stomach, stop reading here.

This is the time GNU make takes.

$ time make jar
javac xmuta.java
jar cvfm xmuta.jar manifest *.class
added manifest
adding: xmuta$1.class(in = 866) (out= 514)(deflated 40%)
adding: xmuta.class(in = 2075) (out= 1100)(deflated 46%)

real    0m0.608s
user    0m0.547s
sys     0m0.099s

And this is the time Apache Ant takes.

$ time ant jar
Buildfile: build.xml

compile:
    [javac] Compiling 1 source file to /home/users/ceving/xmuta

jar:
      [jar] Building jar: /home/users/ceving/xmuta/xmuta.jar

BUILD SUCCESSFUL
Total time: 1 second

real    0m1.544s
user    0m2.099s
sys     0m0.128s

Great isn't it? Only 253% instead of 265%. Can you feel the power of youth?

Now you can understand why it is necessary for a Ant or Maven developer see with every build run the time it takes to build the program. They have to become dulled to endure the misery.

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)