Build Maven, Build ant, Build ivy, Build gradle

Posted on January 16th, 2010 by Reiner.
Categories: English, Computers.

Have a look at Google Trends to see who’s likely to survive :-)

Ok, I’ll admit to be a Maven fan - because it’s the only one that has a holistic concept.

…that will never make it into the heads of people that attempt to reduce complexity to a hammer and all problems to the shape of a nail.

0 comments.

How to persuade Hibernate to accept Nullable Timestamp Columns for Optimistic Locking

Posted on January 13th, 2010 by Reiner.
Categories: Hibernate, Java, Grails, English.

Working on a Grails project that needs to access a legacy database, it proved quite time-consuming to implement optimistic locking in a way that can be handled by Hibernate. Optimistic locking used to be implemented within (legacy) application code and should now be handled by Hibernate completely on its own. For each entity, the legacy schema uses two nullable columns to both trace creation and last updated times as well as to provide optimistic locking capabilities. TS_INSERT holds the Timestamp the entity has been created and TS_UPDATE (initially null) records subsequent mutations to an entity. Just disabling optimistic locking (as well being advertised here) keeps away run time errors but results in an application that cannot meet production quality demands without additional (awkward) application code.

Annotating the TS_UPDATE column with @Version almost did the trick, except it was unable to successfully update entities that had not yet been updated (TS_UPDATE is null). The reason for this behavior is burried within method toStatementString Hibernate Update- and Delete-Code that use TS_UPDATE=? as part of the sql (prepared) statements in order to check for matching old version values. Of course, this condition will always yield false for null values (remember: null = anything including null = null always yields false).

How to cause TS_UPDATE=? to yield true?

Short of changing Hibernate source code I designed a work-around, that effectively changes the TS_UPDATE=? fragment so that it yields true, even for null values. The work-around replaces the TS_UPDATE=? with COALESCE(TS_UPDATE,{ts ‘1900-01-01 00:00:00′})=COALESCE(?,{ts ‘1900-01-01 00:00:00′}). I use the COALESCE function, because it is specified by Ansi SQL 92 Standard and thus should be implemented by most database vendors.

How to alter Hibernate sql statements?

Hibernate provides a rather sophisticated set of interceptor methods, that will be called (back) at certain life cycle stages. Using the onPrepareStatement event, arbitrary changes can be applied to the sql statements that are then sent to JDBC for execution. This is what my interceptor looks like (note that it looks for and… as the version condition will always be appended to the primary key condition - todo: this still needs to be verified for persisting collections):

package com.company.fw.hibernate.util.centura;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.EmptyInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Fixes a shortcoming within Hibernate: Hibernate cannot handle NULL values
 * within optimistic version columns. The where clause will always include
 * e.g. TS_UPDATE=?. We'll try to fix this by changing the sql to e.g.
 * COALESCE(TS_UPDATE,{ts '1900-01-01 00:00:00'})=COALESCE(?,{ts '1900-01-01 00:00:00'}),
 * so that NULL values match.
 */
public class DBcenturaInterceptor extends EmptyInterceptor {

    private static final String PS = "(and) (ts_update)=?";
    private static final String RS = "$1 COALESCE($2,{ts '1900-01-01 00:00:00'})=COALESCE(?,{ts '1900-01-01 00:00:00'})";
    private static final Pattern P = Pattern.compile(PS, Pattern.CASE_INSENSITIVE);

    private final static Logger LOG = LoggerFactory.getLogger(DBcenturaInterceptor.class);

    public DBcenturaInterceptor() {
        super();
        LOG.info("new DBcenturaInterceptor()");
    }

    /**
     * @param sql the sql to be prepared
     * @return and TS_UPDATE=? replaced by
     *         and COALESCE(TS_UPDATE,{ts '1900-01-01 00:00:00'})=COALESCE(?,{ts '1900-01-01 00:00:00'})
     */
    @Override
    public String onPrepareStatement(final String sql) {
        final Matcher m = P.matcher(sql);
        final String result = m.replaceAll(RS);
        if (LOG.isTraceEnabled() && !result.equals(sql)) {
            LOG.trace("onPrepareStatement(" + sql + ") = " + result);
        }
        return result;
    }

}

How to activate the interceptor?

When creating a session, an interceptor can by passed to the Hibernate SessionFactory.openSession(…). As my application is a Grails application, I choose to provide my Interceptor by passing it to the Grails Hibernate session factory, so my interceptor will be used for all and every Hibernate session created within my Grails application. Starting from Grails 1.2, just a single statement is needed within grails-app/conf/spring/resources.groovy:

import com.company.fw.hibernate.util.centura.DBcenturaInterceptor

// Place your Spring DSL code here
beans = {
  entityInterceptor(com.company.fw.hibernate.util.centura.DBcenturaInterceptor)
}

For native Spring applications, have a look at Using a Hibernate Interceptor To Set Audit Trail Properties.

That’s all, take care and have fun :-)

0 comments.

Hibernate Reverse Engineering Tool does not create @TYPE Annotation for User Types within POJOs

Posted on January 9th, 2010 by Reiner.
Categories: Hibernate, Java, English.

Working on a Grails project that needs to access a legacy database, I’ve used the Hibernate Tools for Eclipse and Ant to create annotated EJB3 entity classes.

As the database model uses some peculiar concepts (e.g. char(1) for booleans), I ‘ve created Hibernate custom types that properly map database types to Java types. The Hibernate Reveng Tool can be configured to map certain database columns to custom types, but it fails to create the @Type annotation that is required for custom user types. And as numerous reverse engineering cycle are about to be executed, I didn’t want to fix the generated sources by hand.

There already exists a bug for this problem, but there has been no attempt to fix it during the past two years :-( Thus I’ve designed a work-around and documented it at Issue HBX-849 - Tools does not insert @Type in POJOs for user types defined in reveng.xml :-)

0 comments.

Warum Vodafone und T-Mobile bei Skype zurück rudern

Posted on May 13th, 2009 by Reiner.
Categories: Deutsch, at other Locations, Computers, La Palma.

Z.B. bei heise mobil - 11.05.09 - Vodafone und T-Mobile: Kein Streit mit Nokia wegen Skype-Handy liest man darüber, dass Vodafone und T-Online zuerst jegliche Skype-Nutzung verbieten und blockieren wollten, nun aber doch plötzlich wieder vom Monopol-Saulus zum kundenfreundlichen Paulus mutieren. Warum?

Wahrscheinlich liegt es an der EU!

Bei mir selbst ist das Thema durchaus aktuell: Mein Freund sitzt auf einer Datsche auf den Kanaren und ist nur per Handy zu erreichen. Da klingelt die Kasse, egal wer wen in welcher Richtung anruft.

Deshalb wollen wir ausprobieren, ob und wie das mit Skype funktioniert und ich habe jetzt zuvor versucht zu ergooglen, ob der VoIP- und Skype-Ausschluss, die ich mich entsinne noch vor kurzen in diversen AGBs von Vodafone Spain gesehen zu haben, sich auch auf den “bono prepago” (z.B. 1 Monat / 1GB / danach Drossel für 60€) beziehen.

Es ist wie im Ministerium für Wahrheit: Der String Skype oder sogar auch nur VOIP sind aus allen spanischen Vodafone-Dokumenten spurenlos getilgt. Dafür steht da jetzt überall nur noch P2P. Ich habe an meinem Verstand gezweifelt, bis ich heute auf eine Artikelsammlung unter dem Titel Carriers could by forced by EU to support VoIP services stieß. Ach so ist das :-)

Bin gespannt, ob das nur ein Hütchenspielertrick von Vodafone Spanien ist. Nicht nur technisch ist Skype auch und gerade eine P2P-Anwendung. Die Verbindung und der Transport erfolgen - egal ob Sprache oder File-Transfer - immer direkt zwischen den Skype-Usern.

Die - noch nicht umgesetzte - EU-Drohung könnte auch erklären, warum T-Mobile und Vodafone in Deutschland die Drehrichtung ihrer Schrauben gerade nun umkehren und japsend und für uns überraschend wieder zurück rudern. Insbesondere da Skype eben nicht nur Lieschen Müller ist, sondern neben seiner eigenen Größe noch dazu zu einer illüstren Familie gehört (eBay und PayPal).

Nachtrag: Funktioniert super!

Da müssen Vodafone et al auch Angst bekommen:

Funktioniert 1a - Sprachqualität sogar wesentlich besser (!!!) als per normalem Handy-Anruf, Verbrauch auf der spanischen Handy-Seite 3
kByte/s = 180 kByte/min = ca. 1 Cent pro Minute (bei 60€ / 1 GByte).

Trost für Vodafone: Der Cent geht jetzt direkt zu Vodafone statt zum zum Konkurrenz-Discounter (Yoigo).

Nicht auszudenken, was demnächst alles passieren wird, wenn Nokia jetzt anfängt, Skype flächendeckend in seine Handies einzubauen…

1 comment.

Google Chrome and Java - Needing Both Java 5 and 6 - an Experience in Nightmares - Possible Solution Provided

Posted on March 21st, 2009 by Reiner.
Categories: Chrome, Java, English, Computers.

When you google for Google Chrome and Java you’ll find poor souls that are driven to distraction by Chrome insisting that there is no Java 6 Update 10 or later installed.

Maybe, there are no problems on a clean virgin-like system in mint condition, just unwrapped from its packaging. That’s not mine. I’m a Java developer and all sorts of Java VMs tend to pile up. Right now, I’ll need at least two of them: Java 5 and Java 6.

After an hour of agonizing failures, I found a way to have both Java 5 and Java 6 on my PC and still be able to run Java applets within Google Chrome:

  1. Remove all and every bit of Java, including changes to environment variables (e.g. JAVA_HOME and PATH)
  2. Install Java 6 SDK+JRE (as of now it’s Update 12 - ok for Chrome)
  3. Install Java 5 SDK+JRE unchecking any browser applet integration checkboxes (not sure, whether this is required).
  4. Add any environment variables you might need (pointing to Java 6).

Now I have all three of them, Java 5, Java 6 and Chrome running Java 6 applets :-)

It still puzzles me, I had to install Java 6 first and then Java 5. The other way around would not allow Chrome to recognize Java 6, regardless of any changes being applied to Java within Control Panel…

1 comment.

NetBeans 6.5.1 fixes Nullpointer Exceptions that occurred with 6.5 using Java 6 Update 12

Posted on March 17th, 2009 by Reiner.
Categories: NetBeans, English, Computers.

As I’ve just learnt from Benjamin’s Blog, the Nullpointer discussed yesterday that causes various NetBeans dialogues to fail almost silently when running NetBeans 6.5 with Java 6 Update 12 (6u12) has now been fixed.

And yes, I’m now again able to edit the application descriptor for NetBeans mobile projects :-)

Download NetBeans 6.5.1 now.

See also Error with jdk 1.6.0u12 and Services and NetBeans Issue 157948.

0 comments.

NetBeans 6.5 and Java 6u12 - A No-No!

Posted on March 15th, 2009 by Reiner.
Categories: NetBeans, J2ME, English, Computers.

I recently stumbled upon a problem within a NetBeans mobile project: The editor for the items within an application descriptor would no longer open. Instead a red light on NetBeans frame (all the way down and to the right) would indicate a NullPointer Exception :-(

It appears that the problem is related to running NetBeans 6.5 with Java 6 Update 12.

It appears that other areas and plug-ins might suffer from similar issues as at Do not use JDK 6u12. Use some previous JDK version. We are working on this and NetBeans throws NullPointerException when adding a server.

Update: This bug has now been fixed. Get NetBeans 6.5.1 now.

Work-Around

I don’t know who is the culprit, so just use Java 6 Update 11 (6u11) instead of 6u12:

Download and install Java 6u11 from Sun’s archives or directly from Archive: Download Java Platform Standard Edition (Java SE) 6 Update 11.

Change your NetBeans configuration (e.g. ) to use 6u11 instead of 6u12, e.g.:

# Default location of JDK, can be overridden by using –jdkhome <dir>:
netbeans_jdkhome=”C:Program FilesJavajdk1.6.0_11″

5 comments.

J2ME + Keep-Alive + Chunking = Out-of-the-box + automagically :-)

Posted on March 15th, 2009 by Reiner.
Categories: J2ME, English, Computers.

Wondering about best practices on how to use HttpConnection with J2ME, I had a peek at the sources and to my surprise, I found out, that HttpConnection should offer both keep-alive and chunking without any additional application code (e.g. adding http headers).

The implementation of HttpConnection uses an internal connection cache, so your application code can happily create - Connector.open(”http://…”, …) - and close connections and still transparently re-use the underlying TCP-connections as per HTTP/1.1 Keep-Alive specs, provided the operations being performed on those connections do not preclude Keep-Alives (e.g. by using the request property “Connection Close”, forcing HTTP/1.0, encountering any errors, or just the server plainly rejecting keep-alives).

It is a common misconception, that in order to use Keep-Alive, the HttpConnection object should be kept open. Just don’t do that! Instead always tidy-up resources you’re fed up with, as is the case with HttpConnection that is best used for a single transaction (request-reply) only. HttpConnection will transparently take care of caching the underlying TCP socket connection for you.

HttpConnection appears to be far more powerful than most J2ME programmers suspect. My advice: If you are not completely sure whether a particular option, header or application code is required, just leave it out and see what happens. For instance, HttpConnection will either add a Content-Length header (provided the content does not exceed its output buffer) or enable chunking (again adding the appropriate header) on its own and in a way completely transparent to your application code.

I myself had to learn it the hard way after having set up an implementation for chunking of my own. Not before trying to find out about how to properly interface my implementation to HttpConnection (and peeking at its sources), I realized that it’s all there already - ready to be used for free without even having asked for it :-)

I was able to verify this behavior using a Nokia 6131 NFC mobile device (CLDC-1.1 + MIDP-2.0) and GlassFish v2ur2. It works like a charm!

Notes

The automatic keep-alive may not be what you want when your mobile pays for each second of online access. Keep-Alive can easily be disabled by calling conn.setRequestProperty( “Connection”, “close” );.

Your actual mileage may vary :-( The behavior of the implementation on your phone might be inferior to the one I dealt with (Nokia with lots of implementation code from Sun - judgement derived just from looking at package names) . Nick reports about some of his amazing experiences in his post Using HTTP-Over-Socket and HTTP Proxy in J2ME Applications.

My test responder is implemented in Grails and it succeeds in chunking but fails the keep-alive test (i.e. multiple socket connections are being established) when being run in developer mode from Grails built-in Jetty-Container (i.e. grails run-app). Don’t know (and don’t care), whether this is due to Jetty or Grails running in development mode.

I would have liked to post this as a comment to Codepimps’ article at http://codepimpsdotorg.blogspot.com/2008/12/every-byte-counts.html, however I did not succeed in talking Blogger into accepting my WordPress.com account :-(

0 comments.

Gmail Offline Access with Google Apps Premier Edition outside of the US

Posted on January 31st, 2009 by Reiner.
Categories: English, Computers.

I encountered a tiny problem using Gmail Offline with Google Apps Premier, that might apply only to some non-US countries.

The Create Desktop Shortcuts action does not create any shortcut at all (at the time of this writing and using Google Chrome). So how do I access my mails when offline?

The URL to be used for accessing Google Mail (gmail.com) as given in the help pages does not apply to Google Apps accounts. Normally I just access my Gmail by browsing to http://mail.saddey.net, eventually being redirected to https://mail.google.com/a/saddey.net/. When offline, mail.saddey.net cannot be accessed.

The work-around is both trivial and effective: Just navigate directly to the very same URL that shows up in your browser after invoking Gmail while being online. For convenience, you can create a shortcut of your own just as easily by right-clicking your desktop and selecting New, Shortcut and entering the full URL (from Google’s domain).

Notes: As of now (31-jan-09), using Gmail Offline with Google Apps Premier requires:

  • A browser that is supported by the Google Labs feature (common but up-to-date ones will do)
  • The Google Labs feature (”new features”) to be enabled in your Google Apps domain settings (if you don’t know what this is, please call your admins).
  • The display language no longer needs to be set to English (US), your language might already be supported now.
  • The Google Labs feature to be enabled in your personal Gmail settings
  • Offline to be enabled in your personal Gmail Labs settings

0 comments.

How to send Alert Mails with GlassFish v2ur2

Posted on January 20th, 2009 by Reiner.
Categories: English, Computers.

I’d like to demonstrate GlassFish configuration settings that will cause GlassFish v2ur2 (aka SJAS 9.1_02) to to send alert emails on logging errors or warnings.

A trivial task for an application server that implements a plethora of standards and offers such a slick user interface, I thought.

But I was very much mistaken. Even after having struggled for more than a day, I was unable to identify self management configuration settings that would produce alert mails on any severe or warning entry being logged.

Eventually I succeeded by adopting back level configuration settings from SJAS 8.1 (see Managing and Monitoring Sun Java System Application Server 8.1 - Declarative Alerts at the very bottom). Syntax errors and a package name had to be fixed to get <alert-service> going. What works for me within my domain.xml looks similar to:

      <thread-pools>
        <thread-pool .../>
      </thread-pools>
      <alert-service>
        <alert-subscription name="AlertSubscription1">
          <listener-config listener-class-name="com.sun.appserv.management.alert.MailAlert"
                           subscribe-listener-with="LogMBean, ServerStatusMonitor, HeapSizeMonitor">
            <property name="recipients" value="joe@company.com, jim@service.net"/>
            <property name="fromAddress" value="glassfish@company.com"/>
            <property name="subject" value="Alert From GlassFish Application Server"/>
            <property name="includeDiagnostics" value="true"/>
            <property name="mailSMTPHost" value="my.smarthost.company.com"/>
          </listener-config>
          <filter-config filter-class-name="com.sun.appserv.management.alert.MailFilter">
            <property name="filterWarningMessages" value="false"/>
          </filter-config>
        </alert-subscription>
      </alert-service>
      <management-rules ...>
      </management-rules>
    </config>
    <!-- config model with name "server-config" ends -->
  </configs>

I still would like to know, how to set up mail alerts using self administration settings (e.g. What is the object name to listen for? How to properly install the “default” Custom MBeans with GlassFish PE)?

0 comments.