Monday, December 1, 2008

Hibernate Search 3.1 RefCard

DZone has a nice Hibernate Search 3.1 6-pages ref card. It is packed with:

  • The list of annotations and their descriptions
  • Hibernate Search's main APIs
  • Lucene's most useful query types
  • Quick examples involving mappings and API usage (including the new analyzer declaration framework)

It's free but you need to register.

Speaking of the devil. John and I have given back our last edits for Hibernate Search in Action. So we are still on target for releasing the book in december. I personally still can't believe I am done, so I will play the St Thomas and will wait till I can touch the paper :)

You can get the paper book at Amazon or on the Manning website. Manning also offers the PDF version.

Tuesday, October 7, 2008

Book review and NHibernate Search

Ayende, one of the active bees behind the NHibernate portfolio, has a nice review of Hibernate Search in Action on his blog.

By the way, Ayende has ported Hibernate Search to .net : NHibernate.Search. I don't think there is documentation specific to the project but the Hibernate Search documentation is just as useful.

I don't know Ayende personally, but I can only admire someone that blogs more that I can tweet and still have a full time job :)

Thursday, September 11, 2008

Hibernate Search book preview final review: hitting where it hurts for the better

We just had our third review of Hibernate Search in Action. Receiving this feedback has been a humble experience. Lot's of good reviews (good) and some critical ones (even better). Every imperfection we left aside came back in the spot lights of our reviewers.

Based on this feedback, we have been working hard the last two weeks to improve a lot the manuscript:

  • clearer code transcripts with more inline annotations
  • better separation between different parts of the same example (Hibernate API versus Java Persistence API)
  • the code has been updated to the latest Hibernate Search version and cleaned up a lot (no more warning, same comments as in the book)
  • the code now contains README files for easier navigation, ant scripts, Eclipse and IntelliJ descriptors
  • a nice appendix summarizing all annotations, Hibernate Search APIs and Lucene Query classes
  • added an index: I wish I could plug Hibernate Search on the book, that one was painful
  • added a section on testing (mocking, in-memory integration testing, performance testing)
  • better explanation on how query and analyzer are interwoven
  • add the Explanation API description
  • clearer introduction for each chapter
  • much more references than before making book navigation easier
  • all references in the book are up to date. No more Chapter XX ;)
  • improvements on the clustering chapter

The code is almost ready for prime time, we will publish it as soon as we find the right vehicle for it.

Thanks to all our reviewers. While I am not sure I appreciate the recent sleep depravation, this definitely improved the book a lot.

As usual, you can get the preview version electronically at Manning, it has all the chapters and I hope to get the latest changes uploaded soon.

Friday, August 29, 2008

JarInspector on Mac OS X

There is a tiny little utility that let's you inspect JAR/WAR/EAR files on the Mac OS platform. The software is available here. Install it. To open a JAR, simply right click and chose JarInspector as the application. I personally did not set JarInspector as my default .jar application to let the default JAR launcher kicks in but I have been very close to.

Amongst the useful features:

  • navigate in your jars recursively
  • edit/view files (useful for MANIFEST.MF)
  • decompile a class
  • find a file/class by name

By the way, this utility also opens zip files.

Enjoy.

Thursday, August 21, 2008

Top 5 reasons why Out Of Office messages are wrong

I have always been annoyed quite a bit by automatic Out of Office messages. This summer was no exception. So here are my top reasons for not doing it.

  1. Nobody cares about your trip is Egypt really! If I am sending you an email, I am not on vacations. Do you really want to piss me off?
  2. Email is an asynchronous media. Nobody should expect a synchronous response. If you don't answer a message, a) you are not there b) you don't care: in both cases, there is no point in knowing you are having a good time with uncle Bobby  by the lake.
  3. You pollute mailing lists. When someone, who probably don't even know you, send a message to a mailing list you are a member of, what do you think happen? He receives your vacations post card. Oh and since you are not the only one, he receives vacations cards from 20 other bozos as well.
  4. People forget to disable the out of office message. When you receive a message claiming a person is meant to be back 4 days ago, you wonder if he has been fired or is dead.
  5. Don't reply or send emails when you are in Out of Office Reply. There is nothing more frustrating than being asked a question by mail, reply within 5 minutes and receive a message like "I will not have access to my emails this week"

Please don't overuse this tool. If you need to set that kind of message, it means your organization has flaws.

Monday, August 11, 2008

Hibernate Search in Action: all chapters written

That's now official, I handed over the last chapter to the publisher yesterday. All chapters will be available to the early access program in the next few days. The journey is not finished yet. A lot of reviewing and correction are at sight. If you have feedback, now is the time :)

The last last few chapters out cover:

  • Hibernate Search filters
  • Performance
  • Cluster and scalability

Filters are a neat feature allowing to apply cross cutting restrictions on Lucene queries: you might want to filter to the latest month item creations or filter according to the security level the user is granted. Filters do just that in a declarative fashion: enable one or more of them by their names.

The chapter of performance is a mix of existing content and new content focused around performance at various stages: indexing and searching. It also includes an explanation about index sharding.

The last chapter describes problems that arise when you try to cluster Lucene and how Hibernate Search addresses them. We primarily describe the asynchronous clustering approach implemented out of the box in Hibernate Search (using JMS). The chapter also describes how to customize Hibernate Search to your own clustering strategy to meet your architectural needs.

Now off to the correction marathon :)

Tuesday, August 5, 2008

Remotely send and consume messages with JMS in JBoss AS 5.0

This tutorial will show you how to create a queue in JBoss AS 5 (which uses JBoss Messaging 1.4.1), send a message to a remote queue and listen to the queue using a Message Driven Bean.

I have been playing with JMS queues and MDBs in JBoss AS 5 today to complete the clustering chapter of Hibernate Search in Action and went through more bumps than I should have. Let me share what I've learnt. Disclaimer, I am a JMS noob: this tutorial will go only over the basic concepts. In particular, I will not cover subjects like security, message persistence and so on. This tutorial can be partly reused by Hibernate Search users using clustering (just ignore the part when we send and consume messages as Hibernate Search does that under the hood).

First of all, get a fresh version of JBoss AS 5.0 (currently in Release Candidate 1) here. We will launch two instances of JBoss AS in parallel. If you are lucky enough, run them in two different machines (virtual image or not). If you are not, you will have to remap a few ports to avoid any conflict and this is what I will just describe now.

Go to JBOSS_HOME/server and copy the default directory as master.

cp -r default master

We now have two versions of the JBoss configuration. default will contain our slave instance configuration and master will contain our master instance configuration. Let's now change the default ports on the master configuration. In the master directory, open each file described and change the following ports

  • conf/jboss-service.xml from port 1099 to 1199 (JNDI)
  • conf/jboss-service.xml from port 8083 to 8084 (WebServices)
  • conf/jboss-service.xml from port 1098 to 1097 (RMI)
  • conf/jboss-service.xml from port 4446 to 4447 (Remoting)
  • deploy/ejb3-connectors-service.xml from port 3873 to 3874
  • deploy/jbossweb.sar/server.xml from 8080 to 8081 (HTTP)
  • deploy/jbossweb.sar/server.xml from 8009 to 8010 (Apache connector)
  • deploy/http-invoker.sar/META-INF/jboss-service.xml from port 8080 to 8081
  • deploy/jmx-remoting.sar/META-INF/jboss-service.xml from port 1090 to 1091
  • deploy/messaging/remoting-bisocket-service.xml from port 4457 to 4458
  • deploy/remoting-service.xml from port 4444 to 4443
  • deploy/remoting-service.xml from port 4445 to 4442

This step is only required if you use the same server to run both instances. There is an alternative and more elegant approach described here (thanks Julien for tweeting me the answer after I did all the hard work :) )

You need to make sure JBoss Messaging has a different ServerPeerID between different instances. Update deploy/messaging/messaging-service.xml, and set ServerPeerID to 1 (the default configuration uses 0)

We will now create the queue in the master instance. Open deploy/messaging/destinations-service.xml, and add the following fragment

<mbean code="org.jboss.jms.server.destination.QueueService"

      name="jboss.messaging.destination:service=Queue,name=hibernatesearch"

      xmbean-dd="xmdesc/Queue-xmbean.xml">

      <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>

      <depends>jboss.messaging:service=PostOffice</depends&gt;

</mbean>

A queue is an MBean object, you can refine it's configuration as explained in the JBoss Messaging documentation. As a start, you can simply copy the fragment and replace hibernatesearch by the name of your queue. The queue will be available in JNDI under queue/hibernatesearch (this can be overridden if needed). If you start the master instance of JBoss AS (go to JBOSS_HOME/bin and launch ./run.sh -c master), you should see the following lines in the console

19:27:46,403 INFO [QueueService] Queue[/queue/hibernatesearch] started, fullSize=200000, pageSize=2000, downCacheSize=2000

The next step is to publish a message from the default JBoss AS instance into the queue. Here is a simple servlet doing so:

@Override

public void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    QueueConnectionFactory factory;

    Queue queue;

    try {

        Properties jndiProps = new Properties();

        jndiProps.setProperty("java.naming.provider.url", "jnp://localhost:1199")

        InitialContext initialContext = new InitialContext( jndiProps );

        factory = (QueueConnectionFactory) initialContext.lookup( "/ConnectionFactory" );

        queue = (Queue) initialContext.lookup( "queue/hibernatesearch" );

    }

    catch (NamingException e) {

        throw new Exception( "Unable to lookup queue", e );

    }


    QueueConnection cnn;

    QueueSender sender;

    QueueSession session;

    try {

        cnn = factory.createQueueConnection();

        session = cnn.createQueueSession( false, QueueSession.AUTO_ACKNOWLEDGE );


        TextMessage message = session.createTextMessage();

        message.setText("Pass it along");

        sender = session.createSender( queue );

        sender.send( message );

        session.close();

    }

    catch (JMSException e) {

        throw new Exception( "Unable to send message to JMS queue", e );

    }

    finally {

        try {

            if (cnn != null) cnn.close();

        }

        catch ( JMSException e ) {

            log.warn( "Unable to close JMS connection", e );

        }

    }

}

A few things are noticeable here:

  • we override the JNDI URL to point to the master JNDI host and port: if you run the master instance on a different machine (without remapping ports), the URL will look like jnp://master.host:1099.
  • to look up the factory we use /ConnectionFactory. Do not use java:/ConnectionFactory as this value points to your local instance (I lost a few hours here, thanks Clebert for the hand!). If you want to change this name, open deploy/messaging/connection-factories-service.xml and add a new binding under the JNDIBindings attribute.
  • always close your connection in a finally block to avoid connection leaks

On the master side, you can deploy a MDB (a trivial task with EJB 3 as no deployment descriptor is needed).

@MessageDriven(activationConfig = {

    @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),

    @ActivationConfigProperty(propertyName="destination", propertyValue="queue/hibernatesearch"),

    @ActivationConfigProperty(propertyName="DLQMaxResent", propertyValue="1")

} )

public class MDBPassOnController implements MessageListener {

    private final Logger log = LoggerFactory.getLogger( MDBPassOnController.class );


    public void onMessage(Message message) {

        if ( !( message instanceof TextMessage ) ) {

            log.error( "Incorrect message type: {}", message.getClass() );

            return;

        }

        TextMessage textMessage = (TextMessage) message;

        System.out.println( textMessage.getText() );

    }

}

The new embedded console (to come with JBoss AS 5 final) based on a stripped down version of JBoss ON will make some of these steps much easier but now that you have gone the roots way, don't you feel stronger? :)