Friday, November 20, 2009

More about GWT and Spring

The following was contributed by Yaakov Chaikin (one of the authors of Core Servlets and JavaServer Pages) following some conversations we had regarding an earlier post of mine.
I am only too happy to post it here, with many thanks to Yaakov for taking the time for drafting it.




Let me share one more thing with the readers of Marco's blog. Marco mentioned that he was looking for a more general approach to wiring Spring beans into GWT RPC servlets, so I'd like to offer one.

First, let's explain the basic problem as I understand it. Servlets and Spring beans live in different worlds.

Servlets' lifecycle (when they are created, loaded into memory, initialized, invoked, etc) is controlled by the container (your server). Spring bean's lifecycle is controlled by Spring. So, what does it mean? Well, let me give you an example of what can't be done as a result of this, no matter how you decide to load the Spring's config file and initialize Spring application context:

public class SomeServlet extends HttpServlet {
  @Autowired
  private SomeServiceInterface someService;

  public void doGet(.....)
}

Why won't @Autowired work here? Because for it to work you need Spring to instantiate SomeServlet. Unfortunately, this is not (at least as far as I know, not yet) possible. It's the server's job (according to the spec) to control the lifecycle of SomeServlet and therefore it
gets to decide when to create this class and make it available for requests.

So, you are left with few choices here. Fortunately, Spring helps you out quite a bit here. First, let's look at a way to load Spring configuration without having to write any code. For that, use the
following configuration in your web.xml:

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:/config.xml<</param-value>
</context-param>

<listener>
  <listener-class>
     org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>

Now, you can use the following code in just about any web component that has access to the ServletContext (like a servlet) and pull out the Spring context:

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
...
...
ServletContext servletContext = getServletContext();
WebApplicationContext springContext =
WebApplicationContextUtils.getWebApplicationContext(servletContext);
...

Back to GWT... So, if you want to stop there, you can use the code above in your GWT RPC servlet's init() method (remember, init() will be called only once per servlet and there is only one instance of the servlet ever created by the container, handling all requests in a different thread):

public class MyGWTServlet extends RemoteServiceServlet implements MyService {
  private SomeServiceInterface someService;

  public void init() {
    ServletContext servletContext = getServletContext();
    WebApplicationContext springContext =
        WebApplicationContextUtils.getWebApplicationContext(servletContext);

    someService = (SomeServiceInterface)
        springContext.getBean("someServiceBeanId");
  }
  ...
  ...
}

In my example, "someServiceBeanId" better be configured as a singleton and be thread safe or we would have a serious multi-threading problem on our hands.

However, personally, I didn't want to stop here since I really like the idea of @Autowired together with @Service, @Component, etc.
One huge reason for this is that I use these in such a way that when I stand up my application I will know right away whether or not I messed something up in my code as far as using the Spring configured beans.

For an example of how things can go wrong, consider the servlet code above. Say, I mistyped "someServiceBeanId" and spelled it 'id' (with the lower case i). What would happen when I deploy my web application? Nothing!

Everything would be just fine: no warnings, no errors. I start using my app and everything is still fine. That is until I happen to use some functionality that happens to use that particular GWT RPC servlet. Only then will I be surprised to see a NoSuchBeanDefinitionException. Personally, I'd rather know at deployment time that something is messed up. And the fact that I deploy my web app regularly during development will point out the problem rather quickly.

So, here is the solution that I use:

First, create a SpringRegistry class which looks roughly like this:

@Component
public class SpringRegistry {
public static final String KEY = "springRegistry";

@Autowired
private SomeServiceInterface someService;

@Autowired
private SomeOtherServiceInterface someOtherService;

@Autowired
...

public SomeServiceInterface getSomeServiceInterface() {
return someService;
}

public SomeOtherServiceInterface getSomeOtherServiceInterface() {
return someOtherService;
}

...
}


Now that we have a central bean that can autowire our services, we can define another ServletContextListener to populate that bean in one place. The code for that would look roughly like this:

public class SpringRegistryInitializer implements ServletContextListener {
  /**
   * Spring framework's autogenerated name for the SpringRegistry

      *   component define above.
   */

  private static final String SPRING_REGISTRY_CONFIG_NAME = "springRegistry";

  @Override
  public void contextInitialized(ServletContextEvent event) {
    ServletContext servletContext = event.getServletContext();
    WebApplicationContext springContext =
        WebApplicationContextUtils.getWebApplicationContext(servletContext);

    // Manually retrieve spring registry from spring context
    SpringRegistry springRegistry = (SpringRegistry)
        springContext.getBean(SPRING_REGISTRY_CONFIG_NAME);


    // Store SpringRegistry in servlet context for all web components
    // to be able to retrieve it
    servletContext.setAttribute(SpringRegistry.KEY, springRegistry);
  }

  @Override
  public void contextDestroyed(...) {}
}

ServletContextListener will now make sure that we are autowiring all of my services right from web application initialization (which is before any requests can be accepted by the spec.)

However, we must now remember to configure our new listener in web.xml and we must place our configuration somewhere after our configuration of Spring's ContextLoaderListener.
This is because our listener depends on the Spring context to be already initialized and according to the servlet spec the listeners will be executed in the order they are defined in web.xml.

If you don't want to worry about this condition, you can always do the Spring context loading yourself inside that same SpringRegistryInitializer, but it seems cleaner to me to use the already Spring provided SpringContextLoaderListener.
So, here is how our web.xml will look now:

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:/config.xml<</param-value>
</context-param>

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<listener>
  <listener-class>yourpackage.SpringRegistryInitializer</listener-class>
</listener>

Finally, the code in our GWT RPC servlet can look like this:
public class MyGWTServlet extends RemoteServiceServlet implements MyService {
private SomeServiceInterface someService;

public void init() {
SpringRegistry registry = (SpringRegistry)
getServletContext().getAttribute(SpringRegistry.KEY);

someService = registry.getSomeService();
}
...
...
public void doSomeOperation(....) { //use someService here }
}
Note, once again, that someService better be configured as a singleton and be thread safe or we would have a serious multi-threading problem on our hands.
Also, note that this approach gives you a nice clean separation between Spring and your web application code.

In your servlet or other web component's code you are no longer even retrieving the Spring configured bean through using using the bean's configured ID. It's all hidden from your servlet code inside the SpringRegistry class.

If, for whatever reason, you don't like or are not able to use @Autowired, etc., you can still use this approach and get the benefits of making sure you that if you make a mistake, it will be clear at the first time you deploy to a web container (server).
Just remove all that autowired stuff and inside your SpringRegistry provide setters for the services and use Spring SETTER injection in your Spring config file.

You'll get the same effect.

Sunday, November 8, 2009

rsync on an SSHFS mount point

Turns out that
"If you plan [to] use rsync to sync files from your local machine to your ssh-server, you need "workaround=rename"
Otherwise, you will not be able to update an older version of a file with a newer one. Without this option, you will be able to create files and folders and delete them, but you will get an error like this, if you try to update a file:
rsync: rename "/path/to/file.Q3Btvn" -> "to/file": Operation not permitted (1)

The original entry was from a comment to this entry in Ubuntu Forums; reporting it here, as it was driving me insane (been wasting quite some time trying to figure whether it was a permission issue).

The complete /etc/fstab entry in my system looks something like:
# This mounts the entire filesystem of server on /mnt/server mountpoint
# Use with care!
sshfs#marco@server:/ /mnt/server fuse users,auto,workaround=rename 0 0

However, if you are mounting a Samba file server, and the path contains spaces, beware of the escape code for that being different from the URL one (%20) or the console (\ followed by space; as in: /fileserver/My\ Pictures).

/etc/fstab requires the \040 escape code to mount a filesystem with spaces in its pathname:
# This mounts the Samba share My Pictures on the NFS server 
#fileserver under /media/pictures
//fileserver/My\040Pictures/ /media/pictures cifs user=guest,password=,iocharset=utf8,file_mode=0777,dir_mode=0777 0 0

Sunday, November 1, 2009

Why hashCode() matters

If you have ever overridden the equals() method of Object in your class code (and who hasn't?) you will obviously also re-implemented hashcode() too, following the (ominously scary) warning in the Javadoc of equals():

Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.

Or perhaps not.

The reality is that we developers can be lazy, and sometimes laziness leads to making one assumption too many... such as that, having a sensible implementation of equals() somehow alleviates from the need of re-implementing hashCode() too.

Well, if you are like me, and you haven't heeded Sun's advice, then it's worth noting that this will soon or later bite you, and possibly pretty hard (and, I'd guess rather sooner than later...).

The reason is that the Collections framework make pretty heavy use of hashCode() to speed up such mundane matters as objects lookup and matching; unsurprisingly, especially so in the heavily-used implementation classes such as HashMap and HashSet.

In particular, the contains() method of either Collections will not do an asinine sequential sweep of the entire collection (if the concrete implementation is based directly or indirectly on either of the above two classes) using an equals() test on each element, returning true the first time an equal (in the sense defined by your implementation of equals()) element is encountered, or false otherwise.

Sun's implementation will instead use hashCode() to 'hit' the first possible 'bucket' where the element would have been stored by the HashSet, and, upon finding it (possibly) empty, it will simply assume that the Set does not contain the given element, even though an element that would have been equal (in the sense as defined by your implementation of equals()) is indeed someplace else inside that Set's internal implementation storage.

So, if you do plan to use the Collection framework with your newly-minted class, which you have implemented equals() for, then do yourself a favour and implement a suitable hashCode() too.
In fact, I suggest you do so even if you don't plan to use Collections of those objects: you know Sod's Law, now, don't you?

(and, no, there is no prize in guessing how I found out...)