goldstift's blogspot my 2 cent

13 März 2012

Alternative zu Google? Vielleicht DuckDuckGo

Nachdem Google das Tracking in den Suchergebnissen noch stärker ausgeweitet hat, so dass man mittlerweile noch nicht mal die angezeigten Links kopieren kann, habe ich mich nach einer Alternative umgesehen.

DuckDuckGo (https://duckduckgo.com/) scheint eine solche vernünftige Alternative zu sein. Die Grundsätze "don't track" (http://donttrack.us/) und "don't bubble" (http://dontbubble.us/) machen jedenfalls Hoffnung. Wer sich für die "Technik dahinter" interessiert, sollte einen Blick auf diese Hilfe-Seite werfen: http://help.duckduckgo.com/customer/portal/articles/216392-architecture


DuckDuckGo kann man auch relativ einfach als Standardsuche in Firefox einrichten, so dass durch Eingabe von "?Such begriffe" in der Adressleiste von Firefox direkt eine Suche in DuckDuckGo gestartet wird.
Kurz:
Adressleiste -> "about:config" -> keyword.url = "https://duckduckgo.com/?q="

Eine ausführliche Anleitung gibt's hier: http://help.duckduckgo.com/customer/portal/articles/216441

Ich finde die Ideen teilweise ganz interessant, auch wenn ich statt der "!bangs" (https://duckduckgo.com/bang.html) lieber meine eigenen "Smart Keywords" (http://support.mozilla.org/en-US/kb/Smart%20keywords) nutze, die Firefox seit Version 2.0 bietet.

24 Oktober 2011

SpringRoo: Howto translate Java exceptions to user-friendly error messages

Introduction

This blog post belongs to a tutorial series on SpringRoo 1.2.0 which uses the sample application "photooapp" to provide practical examples.
Within this blog post I will try to explain how you can configure your SpringRoo application to translate well-known exceptions to user-friendly error messages.
By default SpringRoo's exception handling is very basic meaning the technical exception message is directly presented to the user. Our aim is to provide the user with human-readable error messages he (most probably) can understand and react upon.

Basics: Translations in Spring MVC

First of all we need to make ourselves familiar with the translation process in Spring MVC. To translate any given String to the currently set browser locale, Spring MVC uses so called "message codes". These codes are defined in property files which are located in "src/main/webapp/WEB-INF/i18n/application.properties". For each supported locale there will be a separate application.properties file, e.g. application_de.properties for german translations of the message codes. The "application.properties" file must always be used as the fallback reference.

Adding a sample Translation

So let's say, we wanted to translate a "org.hibernate.exception.ConstraintViolationException" which is thrown whenever the user tries to create a "duplicate entry".
Therefore we would add the following line to the application.properties file:
    exceptions.db.duplicateentry=The record could not be saved as there is already a record in the database having the same unique identifier\!

Customize exception JSP

Next we prepare the "uncaughtException.jspx" which is the default JSP for exception handling in Spring MVC. To keep it simple, we'll remove the lines with the "-" and add the ones with "+":
With the help of the little snipped '<spring:message code="${exception.message}" />' Spring searches for a property with the name of the Exception's message in the above named property file. Therefore we "only" need to find a way to set "exceptions.db.duplicateentry" as the Exception's message.

Spring MVC ExceptionResolver

The ExceptionResolver in Spring MVC is used to determine which JSP fits best whenever any Exception is thrown. In my opinion this is the perfect place to perform our little magic. To accomplish this and be able to handle any kind of Exception in the most flexible way I added the following three classes (links lead you to github):
The I18nMappingExceptionResolver is configured via a number of MessageMatchCriteria and wraps the original exception inside an AnalyzedApplicationException. The ladder will then have the translatable property as "message". The I18nMappingExceptionResolver has to be set as the default exception resolver which is done by changing the following in webmvc.xml:
The relevant change is the property "messageMapping" which contains a map of the a fore mentioned MessageMatchCriteria which are mapped to translatable properties. The "classNamePart" can hold a simple or fully qualified class name or just a part of it. The same applies to the "messagePart" attribute - as you can see in the sample above, the term "Duplicate entry" is part of the original exception message and if found will return a different property name than a normal ConstraintViolationException. I should mention that the classPart and the messagePart are searched in the complete stacktrace of the original exception.
Another thing to note is that the AnalyzedApplicationException makes it easy to access the originals root cause e.g. in the JSP as it's accessible via the attribute "rootCause". Therefore the variable "${exception.rootCause.message}" will resolve to the root cause's exception message.

Resume

All the changes have already been done to photooapp so you can review all the changes by taking a look at the following commit statement: https://github.com/aheusingfeld/photooapp/commit/eb9fb0d8b46c50c27a8fdb1e2c01a498fed4b136
Please leave a comment if you have any questions or good advice for improving the blog post series. Thanks in advance.

Further links

Other blog posts of this series

01 Oktober 2011

iPhone: Wartezeit für Rufumleitung bei Abwesenheit setzen

Frage: Wie kann man eigentlich am iPhone die Zeit oder die Anzahl der Klingelzeichen einstellen, die das Telefon wartet, bis ein nicht angenommener Anruf bspw. an die Mailbox weitergeleitet wird?



Antwort:
Diese Weiterleitung nennt man auch "Rufumleitung wenn keine Rufannahme"

Da dies nicht Telefon-spezifisch sondern eine Einstellung in den Systemen des Netzbetreibers ist, gibt es hierfür nicht in jedem Telefon einen Menüpunkt oder eine Einstellungsmöglichkeit. So auch nicht beim Apple iPhone.

Es gibt aber dennoch die Möglichkeit, diese Einstellung über einen sog. GSM-Code zu ändern. Eine Übersicht der meisten Codes gibt es unter http://www.gsmcodes-online.de/
Zur Rufumleitung: http://www.gsmcodes-online.de/Rufumleitungen/rufumleitungen.html

Diese Nummernfolge muss direkt in den Ziffernblock der "Telefon"-App eingetippt werden.

Beispiel "Sprachanrufe nach 30 Sekunden auf die Mailbox umleiten":

**61*MAILBOXNUMMER*11*30#


Meine MAILBOXNUMMER im Telekom-Netz ist z.B. +49151 13 12345678 dementsprechend lautet die ganze Zeichenkette dann

**61*+491511312345678*11*30#


Wie die MailboxNummer bei anderen Providern ist, kann ich leider nicht sagen, man kann aber vorher durch die Eingabe von "*#61#" die aktuelle Einstellung abfragen.

25 September 2011

SpringRoo: Entity-Klassen und JPA-Repositories mit SpringRoo erstellen

Dies ist der zweite Artikel in meiner Tutorial-Reihe zu SpringRoo 1.2.0 in der die Beispiel-Anwendung "photooapp" entwickelt wird.

Vorbedingungen

In diesem Beitrag geht es um die initiale Erstellung der Roo-Anwendung. Hierfür müssen folgende Vorbedingungen erfüllt sein:

Lokalen Datenbankserver installieren (falls notwendig)

Wir gehen davon aus, dass die Anwendung später mit einer MySQL 5.1-Datenbank betrieben werden soll, die auf dem gleichen Server läuft wie die Anwendung.
Um eine ähnliche Umgebung für die Entwicklung zu verwenden, benötigen wir eine lokale MySQL-Installation. Für diejenigen ohne eine lokale Installation ist die wohl einfachste und schnellste Art dies zu erreichen wahrscheinlich das XAMPP-Paket von Apachefriends. Es kann über die URL http://www.apachefriends.org/de/xampp.html heruntergeladen werden.

Ist die Software installiert und der MySQL-Datenbankserver gestartet, können mit den folgenden beiden Befehlen die Datenbank und der zugehörige Benutzer erstellt werden. Diese Befehle sind auch im MySQL-Setup-Skript enthalten:

$ /Applications/XAMPP/xamppfiles/bin/mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.1.44 Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> CREATE DATABASE photooapp DEFAULT CHARSET=utf8;
mysql> GRANT ALL ON photooapp.* TO photooapp@localhost IDENTIFIED BY 'pho!00App';
mysql> exit
Bye
$

Nun sollten alle notwendigen Vorbedingungen erfüllt sein und wir können in der SpringRoo shell weitermachen.

Datenmodell-Klassen in SpringRoo erstellen

Für die Demo-Anwendung "Photooapp" wurde folgendes (vorläufiges) Datenmodell erstellt, das wir nun in SpringRoo umsetzen wollen:

Hierzu öffnen wir die SpringRoo Shell:
ahe:(git)photooapp[master]/$ ~/dev/tools/spring-roo-1.2.0.M1/bin/roo.sh
____ ____ ____
/ __ \/ __ \/ __ \
/ /_/ / / / / / / /
/ _, _/ /_/ / /_/ /
/_/ |_|\____/\____/ 1.2.0.M1 [rev 1fa252f]


Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
...
roo> script --file log.roo --lineNumbers true

Nun gibt es zwei Möglichkeiten:

a) Man tippt die folgenden Befehle auf der Roo-Shell ein:
project de.goldstift.photoo
jpa setup --provider HIBERNATE --database MYSQL --databaseName photooapp --userName photooapp --hostName 127.0.0.1 --password pho!00App

entity --class ~.domain.Tag --activeRecord false --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field string --fieldName lowerCaseName --notNull --sizeMin 2

entity --class ~.domain.Person --activeRecord false --testAutomatically
field string --fieldName lastname --notNull --sizeMin 2
field string --fieldName firstname
field string --fieldName nickname --notNull

entity --class ~.domain.Event --activeRecord false --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field date --fieldName fromDate --type java.util.Date --dateTimeFormatPattern "yyyy-MM-dd HH:mm:ss"
field date --fieldName toDate --type java.util.Date --dateTimeFormatPattern "yyyy-MM-dd HH:mm:ss"

entity --class ~.domain.Folder --activeRecord false --testAutomatically
field string --fieldName title
field date --fieldName createDate --type java.util.Date --dateTimeFormatPattern "yyyy-MM-dd HH:mm:ss"
field string --fieldName systemPath --notNull --sizeMin 1
field string --fieldName urlPath --notNull --sizeMin 1
field boolean --fieldName writable --primitive false

entity --class ~.domain.PhotoFile --activeRecord false --testAutomatically
field reference --fieldName folder --type ~.domain.Folder --cardinality MANY_TO_ONE --fetch EAGER
field string --fieldName filename --notNull
field number --fieldName width --notNull --type java.lang.Short
field number --fieldName height --notNull --type java.lang.Short

entity --class ~.domain.Photo --activeRecord false --testAutomatically
field string --fieldName title
field string --fieldName description
field string --fieldName thumbnail --notNull
field reference --fieldName thumbnailFile --type ~.domain.PhotoFile --cardinality MANY_TO_ONE --fetch EAGER
field reference --fieldName previewFile --type ~.domain.PhotoFile --cardinality MANY_TO_ONE --fetch EAGER
field reference --fieldName originalFile --type ~.domain.PhotoFile --cardinality MANY_TO_ONE --fetch EAGER
field date --fieldName importDate --type java.util.Date --dateTimeFormatPattern "MS"
field date --fieldName shotDate --type java.util.Date --dateTimeFormatPattern "MS"
field set --fieldName tags --type ~.domain.Tag --cardinality MANY_TO_MANY --fetch EAGER
field set --fieldName persons --type ~.domain.Person --cardinality MANY_TO_MANY --fetch EAGER
field set --fieldName events --type ~.domain.Event --cardinality MANY_TO_MANY --fetch EAGER

repository jpa --interface ~.repository.TagRepository --entity ~.domain.Tag
repository jpa --interface ~.repository.EventRepository --entity ~.domain.Event
repository jpa --interface ~.repository.PersonRepository --entity ~.domain.Person
repository jpa --interface ~.repository.PhotoRepository --entity ~.domain.Photo
service --interface ~.service.TagService --entity ~.domain.Tag
service --interface ~.service.EventService --entity ~.domain.Event
service --interface ~.service.PersonService --entity ~.domain.Person
service --interface ~.service.PhotoService --entity ~.domain.Photo

json all
web mvc setup
web mvc all --package ~.web

oder

b) man importiert die Befehle als Roo-Skript (speichern als "log.roo") mit Hilfe des folgenden Befehls:

roo> script --file log.roo --lineNumbers true

Anschließend kann die Anwendung über die folgenden Maven Befehle gebaut und gestartet werden:

ahe:(git)photooapp[master]/$ mvn clean package
(...)
ahe:(git)photooapp[master]/$ mvn jetty:run

Durch letzteren Befehl wird die Anwendung in einem Jetty ApplicationServer gestartet, wodurch sie unter http://localhost:8080/photooapp verfügbar sein sollte.

Die komplette Anwendung ist bei github verfügbar unter https://github.com/aheusingfeld/photooapp


Weiterführende Links

Weitere Artikel der Reihe

23 September 2011

Starting PhotooApp - A SpringRoo tutorial application

Ich hatte bereits im Februar angekündigt, dass ich hier ein paar Artikel über SpringRoo schreiben würde, und nutze nun das Erscheinen des neuen Meilensteins um damit zu beginnen.

Die Idee

Vor ein paar Tagen ist endlich SpringRoo 1.2.0.M1 erschienen, welches der erste sog. Milestone der nächsten Version von SpringRoo ist. Das Besondere hieran ist die Unterstützung des Repository- oder auch DAO-Models, welches im Gegensatz zu dem sog. ActiveRecord-Model steht. Bisher verwendete SpringRoo zwingend das ActiveRecord-Model. Dank dieser Neuerung kann SpringRoo nun endlich in Kombination mit Spring Data JPA genutzt werden, was viele Vorteile und einige neue Möglichkeiten gerade im Bereich der Finder eröffnet.
Mein Ziel ist anhand einer Beispiel-Anwendung/ Demo-App die Möglichkeiten von SpringRoo zu demonstrieren und Workarounds für bekannte Unschönheiten aufzuzeigen.

Auf Grund persönlicher Präferenzen wird die Demo-App eine serverbasierte Fotoverwaltung, die sowohl von mobilen Endgeräten als auch von Desktop-PCs genutzt werden kann. Als Feature sollen die mobilen Endgeräte Fotos und Videos an die Anwendung übermitteln können, so dass diese direkt für andere Nutzer verfügbar sind.


Anforderungen

Hier die bisherigen Anforderungen:
  1. Die Anwendung muss Fotos aus einem Dateisystemordner importieren können
  2. Die Anwendung muss während des Imports Minibilder/ Thumbnails der Originale erstellen, die eine maximale Kantenlänge von 250px haben
  3. Die Anwendung muss während des Imports Vorschaubilder/ Previews der Originale erstellen, die eine maximale Kantenlänge von 1280px haben
  4. Ein Foto hat folgende Eigenschaften
    1. Titel
    2. Beschreibung
    3. Thumbnail-Datei (Fotodatei)
    4. Vorschau-Datei (Fotodatei)
    5. Original-Datei (Fotodatei)
    6. Importdatum
    7. Erstellungsdatum
  5. Eine Fotodatei hat folgende Eigenschaften
    1. Dateisystemordner
    2. dateiname
    3. Breite
    4. Höhe
  6. Die Anwendung soll die EXIF-Daten eines Fotos anzeigen können
  7. Ein Foto muss keinem oder beliebig vielen Stichwörtern zugeordnet werden können
  8. Ein Foto muss keiner oder beliebig vielen Personen zugeordnet werden können, die auf dem Photo zu sehen sind
  9. Ein Foto muss keinem oder beliebig vielen Events zugeordnet werden können
  10. Ein Event hat folgende Eigenschaften
    1. Name
    2. Von-Datum
    3. Bis-Datum
  11. Fotos müssen anhand von folgenden UND-verknüpften Filterkriterien gesucht werden können
    1. Stichwörter (Suchfeld mit Vorschlagswerten)
    2. Personen (Suchfeld mit Vorschlagswerten)
    3. Events (Suchfeld mit Vorschlagswerten)
    4. Name des Dateisystemordners
    5. Titel des Fotos
    6. Erstellungsdatum in gewähltem Zeitraum
  12. Suchergebnislisten müssen eine eindeutige, wiederverwendbare URL haben
  13. Die Anwendung sollte einen Präsentations-/ Slideshow-Modus für Suchergebnislisten unterstützen, welcher die Vorschaubilder der Listeneinträge für jeweils 3 Sekunden anzeigt 

Planung

Diese Anforderungen werde ich in folgende Schritte (und Blog-Posts) aufteilen:

Weitere Ideen und Vorschläge können gerne als Kommentar gestellt werden.

Die Demo-App ist bei Github unter der Adresse https://github.com/aheusingfeld/photooapp verfügbar.

UPDATE 24.09.2011 23:00h:
- Anforderungen in Deutsch übersetzt
- Liste der geplanten Blogposts/ weiteren Schritte erstellt

Vielen Dank für Euer Feedback und Euer Interesse.