Freitag, November 09, 2012

Wiki nur für mich!

Angenervt von unsinnigen MediaWiki Beiträgen? Dann ist das hier die Lösung: Nur noch angemeldeten Benutzern das Editieren erlauben:
$wgGroupPermissions['*']['edit'] = false;
Neuanmeldungen gänzlich verbieten:
$wgGroupPermissions['*']['createaccount'] = false;
Die Einstellungen sind in der Datei LocalSettings.php vorzunehmen. Gefunden auf WikiManual. Ebenfalls interessant könnte das Sperren der Spezialseiten sein. Hier gibt es eine Anleitung zu dem Thema.

Mittwoch, Oktober 03, 2012

URL lokaler Tomcat Server

Mit der Spring Tool Suite ist es denkbar einfach einen lokalen Tomcat Server in Betrieb zu nehmen und ihn mit den entsprechenden Anwendungen aufzurüsten. Im ersten Schritt klickt man sich in die Server-View der IDE. Im zweiten Schritt wählt man die (Web-) Projekte aus, die es auf den Server schaffen sollen. Als erstes prüfe ich die Erreichbarkeit der Anwendung und versuche einen ersten Kontakt über den Browser. Doch welche URL ist hier zu verwenden? Der erste Teil ist relativ klar http://localhost:8080/. In meinen Projekten verwende ich in der Regel Maven. Der Postfix ist dann der XML Eintrag in der pom.xml unterhalb von artifactId. In meinem Workspace verwende ich als Projektbezeichner gerne die artifactId plus die Versionsbezeichnung auf die das Workspace Projekt arbeitet. Unter diesem Postfix findet der Tomcat kein dazugehöriges Projekt. Um nun die tatsächliche URL festzustellen, schaut man am besten in der Server Ansicht unter Apache Tomcat, rechts-klick und open auswählen. Auf dem Modules Reiter findet man das korrekte Postfix für sein Projekt.

Mittwoch, September 05, 2012

Linux MySQL Backup Skript

Als erstes das Backup Skript (Linux Bash Shell):
#!/bin/bash
#filename: backup_mysql.sh
CURRENTTIME=`date '+%Y-%m-%d-%H%M%S'`
FILENAME="preferred_filename-$CURRENTTIME.sql"
mysqldump -d mysql_db_name -u username --password=password > $FILENAME
gzip $FILENAME
Für das Editieren der crontab Einträge stehen die folgenden Befehle zur Verfügung:
# Editieren der crontab mit dem vi
crontab -e
# Auflisten der aktuellen crontab für den aktuellen User
crontab -l
Das Skript möchte ich einmal täglich um 20:20 Uhr ausführen lassen. Dazu lege ich den folgenden Eintrag in der crontab ab (crontab -e starten und ala VI die Konfiguration eingeben):
# m h  dom mon dow   command
20 20 * * * /path/to/file/backup_mysql.sh.sh
Dabei haben die Spalten in der crontab die folgende Bedeutung:
  1. Spalte - Minute 0-59 (mehrere Minuten-Angaben mit Komma, z.B. 0,30 für xx:00 und xx:30 Uhr) * für alle Minuten */5 für alle 5 Minuten (also xx:00, xx:05, xx:10 Uhr, usw.)
  2. Spalte - Stunde 0-23 (mehrere Stunden-Angaben mit Komma, z.B. 10,13,17 für 10:xx, 13:xx und 17:xx Uhr) * für alle Stunden */4 für alle 4 Stunden (also 00:xx, 04:xx, 08:xx, 12:xx, 16:xx und 20:xx Uhr)
  3. Spalte - Tag im Monat 1-31 * für jeden Tag
  4. Spalte - Monat 1-12 * für jeden Monat
  5. Spalte - Wochentag 0-7 (0 und 7 stehen für Sonntag, 1 für Montag, usw.) * für jeden Wochentag
Unschön ist die feste Verdrahtung der Verbindungseigenschaften für die MySQL Datenbank. Beim nächsten mal packe ich die Informationen in eine Konfigurationsdatei.

UPDATE: Eine Idee, wie so etwas aussehen kann, findet sich hier oder hier.

Samstag, August 18, 2012

Migration auf Spring Annotations

Heute war der große Tag. Die alten XML Konfigurationsdateien wurden entfernt und durch die Spring Annotationen @Repository, @Service und @Component ersetzt.

Teil 1: @Repository und die DAOs

Dabei bin ich auf ein erstes Problem gestossen: Die HibernateDaoSupport Klasse wird nicht mehr unterstützt. Weiter wird empfohlen, auf die Klasse org.springframework.orm.hibernate.HibernateTemplate zu verzichten und statt dessen direkt org.hibernate.Session zu verwenden. Das ganze funktioniert ab Hibernate 3.0.1. Für die DAOs habe ich eine gemeinsame Oberklasse definiert: AbstractCommonDao. Diese Klasse definiert die typischen Datenoperationen #findById(...), #delete(...), #save(), etc.. Ein erster Migrationsschritt sieht folgendermaßen aus:

public class AbstractCommonDao extends
        org.springframework.orm.hibernate3.support.HibernateDaoSupport {
    ...
    public final void save(final T t) {
        getHibernateTemplate().saveOrUpdate(t);
    }
}
wird ersetzt durch
public class AbstractCommonDao {
    private org.hibernate.SessionFactory sessionFactory;

    SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public final void save(final T t) {
        getSessionFactory().getCurrentSession().saveOrUpdate(t);
    }
}
Im ersten Schritt sind also alle Codestellen #getHibernateTemplate() durch getSessionFactory().getCurrentSession() zu ersetzen. Problematisch sind im Anschluss die #finder Methoden, da diese keine 1:1 Entsprechung in der HibernateSession besitzen. Die Methode #createSQLQuery(...) findet sich in der Klasse HibernateTemplate wie in der Klasse HibernateSession (Mit dieser Methode können native SQL Anfrage formuliert werden). Bei der Umstellung habe ich alle namenlosen SQL Parameter ersetzt. Das Spring HibernateTemplate unterstützt Konstrukte wie
from match where id = ?
Die HibernateSession kennt keine namenlosen Parameter. Diese Ausdrücke habe ich ersetzt durch
from match where id = :matchId
Für den umgebenden Java Code ändert sich der Aufruf:
public SessionFactory getSessionFactory() {
    return sessionFactory;
}

public Team findByName(final String teamName) {
    List teams = getSessionFactory().getCurrentSession()
            .createQuery("from team where name = :teamName")
            .setParameter("teamName", teamName)
            .list();

    if (teams.size() == 0) {
        return null;
    } else {
       return teams.get(0);
    }
}
Erleichtert also sogar die Lesbarkeit.

Teil 2: Server Start

Nach dem die Konfiguration auf Annotationen komplett umgestellt war, alle JUnit Tests erfolgreich durchliefen, ging es an den Server Start. Meine Anwendung besteht grob aus zwei Artefakten: Der Kern mit der Abstraktion für die Datenbank (Dao, Repository, Service-Schicht) und die Web-Anwendung mit JSPs und Servlets. Die Anwendung läuft auf einem Tomcat 7. Nach Deployment der Anwendung trat dabei beim Hochfahren des Servers die folgende Ausnahme auf:

14.08.2012 17:22:23 org.apache.catalina.startup.ContextConfig
    checkHandlesTypes
WARNUNG: Unable to load class [javax.xml.parsers.SecuritySupport12]
    to check against the @HandlesTypes annotation of one or
    more ServletContentInitializers.
java.lang.IllegalAccessError: class javax.xml.parsers.SecuritySupport12
    cannot access its superclass javax.xml.parsers.SecuritySupport
 at java.lang.ClassLoader.defineClass1(Native Method)
 at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
 at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
        ...
Gefolgt von der Meldung:
INFO: No Spring WebApplicationInitializer types detected on classpath
log4j:WARN No appenders could be found for logger
    (org.springframework.web.context.support.StandardServletEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
14.08.2012 17:22:28 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'betofficeform'
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
Und die Lösung ist die folgende: In der web.xml muss das XML Attribut metadata-complete="true" eingetragen sein!
<web-app id="WebApp_9" version="3.0"
  xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  metadata-complete="true">
Das verhindert, dass die deployten JARs nach Annotationen aus dem Package javax.servlet.annotation durchsucht werden. Ein ähnliches Problem ist in diesem Forum Eintrag beschrieben. Das Problem wurde durch das Löschen der activation.jar aus der Maven Dependency Liste gelöst.

PHP Horror

Bei der Installation von PHP, Pear, PHPUnit bin ich auf verschiedene Probleme gestossen. Wie üblich haben die Versionen der einzelnen Module nicht mit einander harmoniert. Hier einfach mal ein Auszug meiner Installationskommandos:
sudo apt-get install php-pear
sudo pear channel-update pear.php.net
sudo pear upgrade-all
sudo pear channel-discover pear.phpunit.de
sudo pear install -a phpunit/PHPUnit
pear config-set auto_discover 1
pear install pear.phpunit.de/PHPUnit
Bzw. auch eine Empfehlung...
sudo apt-get remove phpunit
sudo pear channel-discover pear.phpunit.de
sudo pear channel-discover pear.symfony-project.com
sudo pear channel-discover components.ez.no
sudo pear update-channels
sudo pear upgrade-all
sudo pear install --alldeps phpunit/PHPUnit
sudo pear install --force --alldeps phpunit/PHPUnit
Und falls Curl fehlt vielleicht auch das:
sudo apt-get install php5-curl
Und noch den hier:
sudo apt-get install php-pear
sudo pear channel-update pear.php.net
sudo pear upgrade-all
sudo pear channel-discover pear.phpunit.de
sudo pear channel-discover components.ez.no
sudo pear channel-discover pear.symfony-project.com
sudo pear install -a phpunit/PHPUnit
Und falls du unter PHP 5.3 arbeitest, kann es evt. Sinn machen, den strikten PHP Übersetzer etwas zu lockern:
error_reporting = E_ALL & ~E_DEPRECATED
Das hat zumindest einige Probleme mit den Pear Bibliotheken behoben. Die Einstellung muss natürlich in der php.ini hinterlegt werden.

Virtual Server Update

Hier einige Merker und Tipps für ein Upgrade the Virtual Server Umgebung bei HostEurope.
  • Password für das Plesk Parallels Panel vergessen? Mit der Abfrage /usr/local/psa/bin/admin --show-password über eine Root-Shell kannst du dir das Password anzeigen lassen.
  • Wo finde ich das MySQL Password? Wieder gibt es dafür eine Abfrage cat /etc/psa/.psa.shadow;echo.
  • Installationshinweise für ein JDK 7 unter Ubuntu 10 habe ich hier gefunden. Hier gibt es eine weitere Beschreibung.
  • Aber auch ganz einfach:
    sudo apt-get install openjdk-7-jdk
  • Die aktuelle PEAR Version für PHP war auf meiner virtuellen Maschine bereits vorinstalliert. Bei der Ausführung der PHP Skripte kam es dann aber zu einer Fehlermeldung, dass die entsprechenden PEAR Skripte nicht gefunden werden können. Korrekt installiert finde ich PEAR im Verzeichnis /usr/share/php/. Als erstes habe ich in der Datei /etc/php5/apache2/php.ini den include Pfad angepasst: include_path = ".:/usr/share/php". Eventuell ist eine weitere include_path Zeile auszukommentieren, die meine Einstellung wieder überschreibt. Damit PHP Dateien öffnen und beschreiben kann, ist die Variable open_basedir ebenfalls anzupassen und der Pfad aus include_path hinzuzufügen.. Als letzte Einstellung sind die Dateirechte zu überprüfen.
  • Das Umstellen der Domain Namen auf die neuen IP Adressen kann bis zu 24 Stunden dauern. Unter Windows kann der DNS Cache mit dem folgenden Kommando gelöscht werden:
    ipconfig /flushdns
    Firefox besitzt einen eigenen DNS Cache, der mit der Eigenschaft network.dnsCacheExpiration=0 (Integer) gesteuert werden kann.
  • Firefox speichert die Eigenschaften in der Datei c/Users/winkler/Anwendungsdaten/Mozilla/Firefox/Profiles/xxxxxxx.default/prefs.js. Einige Eigenschaften für den Firefox lassen sich nur über diese Datei ändern.
  • Plesk legt die VHOST Logdateien unter den folgenden Pfaden ab: /var/www/vhosts/<domain_name>/statistics/logs/access_ssl_log und /var/www/vhosts/<domain_name>/statistics/logs/error_log.

Tomcat und UTF-8

Laut Dokumentation verarbeitet der Tomcat Container per Default das Encoding ISO-8859-1 (siehe Tomcat Wiki oder HTTP 1.1 Spezifikation des W3C). jQuery verwendet per Default für das Senden von Ajax Events das Encoding UTF-8 (Siehe dazu in der jQuery Beschreibung). Im ersten Schritt muss dem Tomcat beigebracht werden, Request mit dem für uns richtigen Encoding zu verarbeiten. Dazu muss die Datei server.xml im conf Verzeichnis der Tomcat Installation angepasst werden (Eine Beschreibung findet sich zu diesem Thema ebenfalls hier). Dazu wird die Connector Definition um das Attribut URIEncoding="UTF-8" erweitert.
<Connector port="8080"
    protocol="HTTP/1.1"
    connectionTimeout="20000"
    redirectPort="8443"
    URIEncoding="UTF-8"/>
Im Anschluss ist dafür zu sorgen, dass das ausgelieferte Response ebenfalls mit UTF-8 kodiert wird. Dazu gibt es die folgende Möglichkeiten.
  • Innerhalb einer JSP Seite:
    <%@ page language="java"
        contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
        
  • Für HTML 5 (Angabe über das Meta Tag):
    <meta charset="UTF-8">
        
  • Für HTML 4:
    <meta http-equiv="Content-type"
        content="text/html;charset=UTF-8">
        
Dabei ist sicherzustellen, dass die ausgelieferten Daten ebenfalls UTF-8 kodiert sind. Im einfachsten Fall ist der HTML Editor auf das entsprechende Encoding einzustellen.
Zum Abschluss noch ein Link mit einer Erklärung über den Unterschied von GET und POST: GET versus POST

javax/validation/Validation

Heute ließ sich in einem meiner Java Web Projekte die JUnit Tests nicht ausführen mit der folgenden Fehlermeldung:

testXyz(de.betoffice.ws.HessianServiceTest):
  Error creating bean with name
  'mySessionFactory' defined in
  class path resource [betoffice-persistence.xml]:
  Invocation of init method failed; nested
  exception is java.lang.ClassFormatError:
  Absent Code attribute in method that is
  not native or abstract
  in class file javax/validation/Validation
Auf Stackoverflow habe ich eine Lösung gefunden. Ich frage mich nur, wieso benötigt das Projekt 'jetzt' ein JAR mit javax/validation/Validation?

UPDATE 30.12.2011 08:00 Uhr: Und heute funktioniert der JUnit Test wieder nicht. Trotz obiger skizzierter Lösung. ?!??? Irgendwas ist an meiner Umgebung faul.

UPDATE 30.12.2011 15:54 Uhr: Jetzt funktioniert der Test wieder. Ich habe die Reihenfolge der Dependencies in der pom.xml verändert. Die Einträge

  <dependency>
    <groupId>javax.validation>
    <artifactId>validation-api</artifactId>
    <version>1.0.0.GA</version>
  </dependency>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.0.2.GA</version>
  </dependency>
stehen jetzt ganz vorne. Eine Erklärung habe ich erst einmal nicht.

AssertJ und java.util.List

AssertJ hat eine praktische Möglichkeit, Listen in JUnit Tests abzuprüfen. Insbesondere, wenn in der Liste komplexe Objekte abgelegt sind, s...