Wednesday, May 2, 2012

Activate Maven profile for Jenkins


I have been banging my head on a stupid typo lately. A profile associated with an environment variable of Jenkins wouldn't become active. For a multi-module Maven project.

Before - it does not work. It seems to work for the modules though.


<profiles>
    <profile>
      <id>jenkins</id>
      <activation>
        <property>
          <name>BUILD_NUMBER</name>
        </property>
      </activation>
      <build>


After - now it works everywhere. Just forgot to put the "env." in front. :-)

<profiles>
    <profile>
      <id>jenkins</id>
      <activation>
        <property>
          <name>env.BUILD_NUMBER</name>
        </property>
      </activation>
      <build>

Friday, April 27, 2012

Amazing Pangolin !

Ladies and Gentlemen, this is an historical moment... Never before, for all those years using Linux. Never, ever, before ...

... wasn't my machine killed by a regular distribution upgrade ! This is the result of a long perseverance - I've tried an upgrade for each new release. All did fail. But not any more ! Never mind the HUD ! Long live the working upgrades ! :-)

Congratulations to the Canonical team ! (no kidding this time)

Wednesday, April 25, 2012

Nice user agent parsing library

Do you need to know about your users' browser or operating system ? Mobile or desktop ? Do you want to ignore requests from bots ?

For that I can certainly recommend UASparser. A lightweight, yet fast, updatable and very effective library used to interpret the http user-agent header. It extracts client data from the header based on a definition file. 

The definitions can be downloaded from the internet by your application. Or from a local file deployed with the application.

The few trials I did were exactly what I needed: Is it a mobile browser ? Android ? iOS ? A regular desktop browser ? Etc...

The only issue I had is that it is not on Maven Central. Yet. :-)

Thursday, March 22, 2012

Migrate to Hibernate 4 & EhCache

Our Jenkins continuous build is sometimes running into weird errors. On one occasion the 2nd level caches died and on another entities are missing once Hibernate Search was included.

As on both occasions Hibernate seems to be involved, it looks like a good idea to upgrade Hibernate from 3.x.x to 4.x.x.; to work around the problem. In the end it proved not too difficult. If only EHCache didn't put up a fight. :-)

1. Replace the Hibernate version in pom files
Everywhere where it reads 

    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-*****</artifactId>
      <version>3.x.x</version>
    </dependency>


Replace it with


    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-*****</artifactId>
      <version>4.x.x</version>
    </dependency>



At the time of this writing "3.6.10.Final" was replaced by "4.1.1.Final".

2. Replace the Hibernate Search version in pom files
Everywhere where it reads 

    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-search</artifactId>
      <version>3.x.x</version>
    </dependency>


Replace it with


    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-search</artifactId>
      <version>4.x.x</version>
    </dependency>



At the time of this writing "3.4.2.Final" was replaced by "4.0.0.Final". 

3. Include CGLIB
There seems to be a hidden dependency with CGLib. Otherwise you'll get an error as soon as your application starts.

org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.

Add this xml fragment to your pom file:

    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>2.2.2</version>
    </dependency>



4. Replace EHCache
If you won't replace EHCache, you'll get ClassNotFound exceptions:

Caused by: java.lang.NoClassDefFoundError: org/hibernate/cache/TimestampsRegion
Caused by: java.lang.ClassNotFoundException: org.hibernate.cache.EntityRegion

The problem seems to be that for Hibernate 4 you should not use EHCache explicitly. But rather use Hibernate's EHCache implementation.

Remove the following from your pom file:

    <dependency>
      <groupId>net.sf.ehcache</groupId>
      <artifactId>ehcache-core</artifactId>
      <version>****</version>
    </dependency>


And replace it with:



    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-ehcache</artifactId>
      <version>4.x.x</version>
    </dependency>
The version must be the same as the version of Hibernate. At the time of writing "4.1.1.Final". Make sure to keep these in sync when upgrading even further.


5. Redefine the cache factory
Because EHCache was replaced it's also needed to tell Hibernate to use a different class for creating caches. Because there are many ways this can be defined, rather search in your files for the string "hibernate.cache.region.factory_class". Typically you'll find xml configuration files assigning a value to that property.


The assigned value should now read something like: org.hibernate.cache.ehcache.EhCacheRegionFactory. 


Typically this formerly was the name of a class in the package net.sf.ehcache.hibernate.


6. Remove multi-module project from repository
Our application is a multi-module project, with some modules depending on each other. I had to remove the files from the local repository to make it finally work.

So, that's it. It didn't solve my original problem. But at least the application is upgraded. And the way has been set to replace EHCache with Infinispan.


Hope this was useful for somebody somewhere. :-)

Wednesday, March 21, 2012

There is life after death - sorry - after IT consulting !

Today I've told on a mailing list - by accident - I was glad I got out of IT consulting. Never to come back. As a reward I was challenged to elaborate on that. Right... But then again, it's no secret. This is the occasion to get it off my chest then.

It's a long lecture though ! I didn't know I had so much to get off.  :-)

Keep in mind though this is about IT consulting in Belgium. And in my little country a consultant usually isn't freelance. But rather employed by a company which business is to send their people - consultants - to work onsite for IT projects. Usually at the customers headquarters. So bear with me if in your country "IT consulting" means something else entirely. :-)

Personally I think the idea of IT consulting as described above is okay. In theory that is. You have a company car, advantages and are usually well paid. Materially speaking, there's usually nothing to complain about. You'll be in touch with much technologies, people, domains, etc... If you can keep up the pace, you'll prove your worth and you'll become a living encyclopedia of software development.

The latter is something I personally appreciate. Because learning is something I like in this profession. And never can get enough of it. I never miss Devoxx and am always reading a book or three. The reading backlog almost literally reaches up to the ceiling.

Alas, from back in the nineties to now I've seen consulting becoming a grim, absurd and impersonal branch of the trade. Being a consultant used to be reserved for the best. And the longer you did this profession, the more you were respected for that. At Oracle Consulting, the principals had a god-like status. Because they really could do impressive things. And were given prestigious projects. It made no doubt their rank was well-deserved.

But today... With all due respect, consultants are considered cannon-fodder. I can't speak for everywhere in Belgium of course. But I my case I can certify it declined steeply in the last decade. 

So... Why did I leave ?
  1. It's impossible to specialize. The direct managers are indifferent to the experience of their subordinates. They're resources they have to allocate asap to a project. Regardless whether this makes sense or not. Even if a better match is about to become available. I'm talking about a match concerning experience/place/profits. And how many times it appears later they didn't even care to check for projects when it was known when the current project would end ? Arguing is usually a bad idea for your next evaluation.
  2. There's no consideration for the consultants. How often did my direct manager say something that implies he's plain ignorant of the technologies his subordinates apply ? Or that he just don't care ? It's not exactly surprising then he'll be trying to put you at work any place that's available next. (I've got a perfect match for you. You're developing software, right ?) Consultants are people perfectly capable of deducing facts from what is (not) told to them. Because applying logic is our trade.
  3. Keep eyes in your back. The last years I took the habit to keep a project journal. It served me on occasions to refute accusations of incompetence from my own hierarchy. I still keep a journal. Even if it's just for looking back what I did.
  4. You're on your own. Another consequence of not being considered by your manager is that he won't protect you from the surreal decisions of his managers. He simply drops it down on his own people. Don't try to argue either. With the known results if you do. Another evidence these managers don't care about their people.
  5. There is no training. My personal experience is that you have to cope with anything thrown at you. Which happens quite a lot because they drop you in the first starting project. Which is usually urgent to start. So there's no time for training. Etc... It is coincidence if you already knew something about the technologies the customer wants to apply. 
  6. It is very hard to get a raise. Personally I've got my raises when changing jobs. It looks like they don't care you leave. If you leave you'll be replaced anyway. So why bother paying you more ? You better negotiate well when applying for the job. Because getting something after that will be difficult. I remember for one of my employers I had to ask the customer to send feedback about my work onsite - right before my evaluation. Because I knew my manager wouldn't bother to ask for it to the customer. So, how can they actually tell you're any good ?
  7. Brown-nosing pays. Unfortunately, very often this brings you a lot further than proving your valor at work. Also for getting the "good" projects. You'll have a much easier life if you do. I know quite some managers being sensible to that. They're usually also sensible in the opposite way when not being flattered. I belong to the latter kind. But I don't regret it. I was well-considered by my siblings and customers. 
  8. There's no long-term for technical consultants. In consulting you either go sales (not me), management (been there, done that, ran away) or technical. In the latter case you go from junior (and ignorant) to principal (been there for some time already). The latter case knows only two kinds who stay: the submissive kind (not daring to say no) and the flattering kind. If you are neither, you'll be in conflict very quickly with your manager. Because you're not impressed any more and thus argue the sense of things. Which they don't like. I can assure you that I wasn't known to be rude. But I got my share of reactions nonetheless.
Finally, at the end of the day, I had an illuminating moment that I got "too old for this shit". I like my job but I don't want to flatter or be submissive to keep it. Hence it was time to move on and leave it permanently behind. It is a kind of job one does not forever anyway. At least now I know why there are almost no "old" consultants left.

One might ask whether there is any good being a consultant today ? Yes, there is: If you're young and willing to learn fast. You will be able to start easily, earn descend money and will be learning a lot very fast. But not otherwise. 

To be honest, I'd rather say you don't start in IT consulting at all. Spend instead more time to find something in a domain you're personally interested in. It will take longer, but it will pay off. Even if you won't earn as much in first time. 

And in the end... you might even be respected for your accomplishments !

Thursday, March 15, 2012

RTFM !!!

Just had the polite advise from one of our software suppliers to read "these excellent resources" for my repeated questions about using CSS in their software.

Very subtle indeed ...

Tuesday, March 13, 2012

JPA Suicide Code

For the application I'm currently developing the administrators should be able to purge the database. Since the application is not allowed to drop and recreate its own schema, it has to be done the hard way.

Hence this little code fragment. It takes an EntityManager as input (variable em) to find out what entities classes there are. From there it tries on and on to remove the entities of each found entity class.

Hope this comes in handy for somebody else too...

EDIT: The rollback might fail due to the transaction being inactive. I've modified the code accordingly.

EDIT: After deleting entities a flush is now explicitly needed. Probably due to the upgrade to Hibernate 4. But whether this is a configuration or coding problem ?

// (1) Get the entities this em is managing
final Metamodel metamodel = em.getMetamodel();
final Set<ManagedType<?>> types = metamodel.getManagedTypes();

// (2) For as long as the queue contains types to purge
while (!types.isEmpty()) {

  // how many types we start with ?
  final int typeCountBeforeDelete = types.size();

  // start killing off entities
  final Iterator<ManagedType<?>> iterator = types.iterator();
  while (iterator.hasNext()) {

    // what's this type about ?
    final ManagedType type = iterator.next();
    final Class clazz = type.getJavaType();
    final Entity entityAnnotation = (Entity) clazz.getAnnotation(Entity.class);

    // Is it non-entity or abstract type ? => ignore
    if (entityAnnotation == null ||  Modifier.isAbstract(clazz.getModifiers())) {
      iterator.remove();
      continue;
    }

    // it is an entity => try to remove all its occurrences
    final String name = entityAnnotation.name().equals("") ? clazz.getSimpleName() : entityAnnotation.name();
    em.getTransaction().begin();
    try {
      final Query all = em.createQuery("from " + name);
      for (final Object entity : all.getResultList()) {
        // em.remove() must be used in order to have the cascading working.
        // Using JPQL won't trigger the cascades => risk of circular referential constraints.
        em.remove(entity);
      }
      em.flush(); // Hibernate 4 only ?
      em.getTransaction().commit();

      // Deleted worked => remove type from the queue
      iterator.remove();
    } catch (Exception e) {
      // if the error happened during the commit, then the transaction might not be active any more.
      if (em.getTransaction().isActive()) {
      // delete didn't work - yet - maybe the referential integrity prevents it for now
      // next cycle will take care of it.
        em.getTransaction().rollback();
      }
      // guess the meaning of the error message.
      if ( !e.getMessage().toLowerCase().contains("constraint") && !e.getCause().getMessage().toLowerCase().contains("constraint")) {
        throw new IllegalStateException("Error while purging database",e);
      }
    }
  }

  // How many types left ? It *must* be less than before the delete. Otherwise
  // we're having a circular referential integrity check somewhere.
  // Trying again is useless.
  if ( types.size() == typeCountBeforeDelete ) {
    throw new IllegalStateException("Can not delete any more data => circular referential integrity constraint very likely.");
  }
}