Thursday, December 23, 2010

Spring MVC ModelAttribute and BindingResult

The Problem:

I am using Spring 3 MVC and I encountered the following error upon form submission:

org.springframework.validation.BindException type mismatch

In my controller I defined the following 2 model attributes:

        model.addAttribute("gene",gene);        
        model.addAttribute("renameAllele", ra);

Upon form submission, I wanted to bind the ModelAttribute to my method arguments as follows:

    @RequestMapping(value="/renameAllele/submit", method=RequestMethod.POST)
    public String submit(@ModelAttribute("renameAllele") @Valid final RenameAllele ra, BindingResult alleleBindingResult, 
            @ModelAttribute("gene") RenameGene gene, SessionStatus status ) {

This method signature didn't work because for every ModelAttribute added, we need to have a corresponding BindingResult argument as well. As you can see above, the ModelAttribute("gene") did not have a corresponding BindingResult.

Solution

To get it working, I changed the method signature as follows:

    @RequestMapping(value="/renameAllele/submit", method=RequestMethod.POST)
    public String submit(@ModelAttribute("renameAllele") @Valid final RenameAllele ra, BindingResult alleleBindingResult, 
            @ModelAttribute("gene") RenameGene gene, BindingResult geneBindingResult, 
            SessionStatus status ) {

I figured this out by reading the spring reference documentation. Here is a quote taken from their site:
"The Errors or BindingResult parameters have to follow the model object that is being bound immediately as the method signature might have more that one model object and Spring will create a separate BindingResult instance for each of them so the following sample won't work:"
Reference: http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html

Tuesday, December 21, 2010

styling tables made easy with DataTables jQuery plugin

In the past I've usually formatted results into a table using 'zebra' styling where each alternating row would be shaded with a different background color. Below is an example:




Typically the JSP would look as follows:


<table cellspacing="0" class="tracker-summaries">
    <tr>
        <th>Procedure</th>
        <th class="right-col">Version</th>
        <th class="right-col">Date added</th>
        <th class="right-col">Filename</th>
        <th class="right-col">&nbsp;</th>
    </tr>
    
    <c:set var="rownum" value="0" />    
<c:forEach items="${procedures}" var="procedure" >
                
        <c:set var="rownum" value="${rownum + 1}" />
        <tr <c:if test="${rownum mod 2 == 1 }">class="odd"</c:if>>
            
            <td>${procedure.type.value }</td>
            <td class="right-col">${procedure.version }</td>
            <td class="right-col">
                <c:if test="${not empty procedure.dateCreated}">
                    <fmt:formatDate pattern="dd/MM/yyyy" value="${procedure.dateCreated}" />
                </c:if>
            </td>    
            <td class="right-col">                
                ${ procedure.filename }
            </td>
            <td class="right-col">
                <a href='<c:url value="/inventory/inventoryDocDownload.html" />?<%= ParamNames.TYPE %>=<%=InventoryDocDownloadController.TYPE_PROCEDURE%>&id=${procedure.id}'>Download</a>
            </td>
        </tr>    
            </c:forEach>

</table>

As highlighted in red, I would manually assign each alternating row a different style to achieve the 'zebra' look and feel. This worked fine, but it became quite repetitive when you have multiple pages listing results in tables.

I recently, discovered a much better solution without having to customize each JSP that contained tabular results, using a jQuery plugin called DataTables

It's really quite simple. You create your tables without any styling attached. Then invoke a few lines of jQuery code to apply styling dynamically as follows:


    <script type="text/javascript">

        $(document).ready(function() {
            oTable = $('table.display').dataTable({
                "bJQueryUI": true,
                "bPaginate": false,
                "bLengthChange" : false,
                "bFilter" : false                            
            });

            $(".ui-toolbar:first").css('display','none');            
        } );        
    
    </script>

If you can apply this to every header to of your page, then all your pages will automatically have their tables properly formatted.

Furthermore, your tables will automatically have sorting, searching and pagination built-in.

Monday, December 20, 2010

SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'

In Tomcat I had a stale version of context.xml under the following folder

/conf/Catalina

By deleting this cached folder the error was resolved

Spring 3 jndi-lookup and Tomcat

In your spring configuration you may have something like:

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/facs"/>

Then in your webapp /META-INF/context.xml file you should have something similar too:

<?xml version='1.0' encoding='utf-8'?>

<!-- antiResourceLocking="true" -->
<Context path="/podd-apn"
         reloadable="true"
         cachingAllowed="false"
         antiResourceLocking="true"
         >


  <Resource name="jdbc/facs"              
            type="javax.sql.DataSource" username="${database.username}" password="${database.password}"
            driverClassName="org.postgresql.Driver" 
            url="${database.url}"
            maxActive="8" maxIdle="4"
            global="jdbc/facs" 
            />


</Context>


And in your web.xml you should something like:

  <!-- JNDI -->
  <resource-ref>
    <description>FACs Datasource</description>
    <res-ref-name>jdbc/facs</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref> 

Wednesday, November 24, 2010

Transcaction not successfully started

If the exception is coming out of a commit operation, try the following:

if(!trans.wasCommitted){

trans.commit;
}

Tuesday, November 23, 2010

OpenSessionInViewFilter singleSession=false, Illegal attempt to associate a collection with two open sessions

In previous configurations I've been setting the singleSession=true in the OpenSessionInViewFilter provided by spring. This parameter binds a Hibernate session to the request. However, this proved to be problematic in our scenario because we were caching the POJO entities in a cache store that lives outside of Hibernate's caching mechanisms. Why we are having another caching mechanism is irrelevant, but for sanity sake, I'll just say that we have different datasources that are combined into a single entity, which makes caching important for performance reasons.

Since this cache store is accessible by all incoming requests, POJO's that were added to the cache by previous requests, were still associated with the session bound to the previous request (that were lazily loaded). In an asynchronous environment, this led to the following Hibernate exception: Illegal attempt to associate a collection with two open sessions

To resolve this issue, I needed a way for multiple requests to share the same object loaded from the cache store. That is, I needed a way to unbound the session to the request and allow for multiple sessions within a single request. To do this, I changed the singleSession=true for the OpenSessionInViewFilter.

The thing to be aware of is now all data accesses should be wrapped in Transactions. To do this I used spring's annotations:


@Transactional(propagation=Propagation.REQUIRED, readOnly=false)public class FedoraPoddObjectDAOImpl extends AbstractFedoraDAOImpl<PoddObject> implements PoddObjectDAO

Monday, November 22, 2010

Caching Hibernate Proxied Objects

Generally, caching objects that have loaded from database helps to improve performance when retrieved several times. However, there is something to be aware of when lazily loading objects from hibernate and putting them into the cache store.

If you're like me, and you're using spring's OpenSessionInViewFilter and a cache store to store objects, you might encounter the dreaded LazyInitializationException.

Here's why:

Say you access the same object over several web requests:

Request #1: 
 1) OpenSessionInViewFilter opens a new session
 2) You load the object from hibernate but never actually retrieve it's lazily loaded proxied associations. 
 3) The object along with its proxed associations, gets stored in the cache
 4) OpenSessionInViewFilter closes the session. The proxy object no longer has it's session opened.


Request #2:
1) OpenSessionInViewFilter opens a new session
2) You attempt to load the same object from the cache. A match is found and the cached object is returned.
3) You attempt to load associated objects that are proxied.


Step 3, is where it fails with LazyInitializationException because, the session was already closed.


Solution:


Reattach the cached object to the session.


    @Override
    public void reattach(T entity) {
        Session session = getSession();
        try {
            if (PoddObject.class.isAssignableFrom(entity.getClass())) {
                PoddObject po = (PoddObject) entity;
                Long id = po.getId();
                if (id != null) {
                    try {
                        session.buildLockRequest(LockOptions.NONE).lock(entity);                    } catch (NonUniqueObjectException e) {
                        LOGGER.info("Merging entity instead of locking");
                        session.merge(entity);
                    }
                }
            } 
        } catch(HibernateException e) {            
            LOGGER.warn(e);
        } finally {
            releaseSession(session);            
        }
        
    }


Hibernate Lazy proxied objects and instanceof operation, type casting

Lazy loading of associations in Hibernate will help improve load time and keep performance reasonable. But there are some things to be aware of when lazily loading objects. The one I'm going to talk about today is the issue of using the instanceof operator and casting on a proxied object.

Say we have an inhertiance strategy where class Person is the super class, and class Student is a sublcass of Person.



If we configure hibernate to lazily load objects of class type Person, then Hibernate will create a proxied object that extends from class Person and not class Student even if the true class type of the object is a Student.

Then the following code will not work:

Person person = lazyLoadFromHibernate(id); // The proxied object from hibernateif (person instanceof Student) { // Fails on proxied object
    Student student = (Student) person; // Fails on proxied object
}

This becomes a real pain, when you already have this type of code everywhere in your application. The easy fix would be to set lazy="false" and enforce no proxied objects, but then your performance would take a hit.
So I implemented a solution that would always load the true object by replacing the proxied object with a fully initialized object and maintaining performance as follows:

    public static <T> T initializeAndUnproxy(T var) {
        if (var == null) {
            return null;
        }

        Hibernate.initialize(var);
        if (var instanceof HibernateProxy) {
            var = (T) ((HibernateProxy) var).getHibernateLazyInitializer().getImplementation();
        }
        return var;
    }

But I didn't want my application code at the business layer to be aware of Hibernate, so I implemented a Tuplizer and overrided the afterInitialize(). For example, if a Person object is associated with a Student object via a "classmate" relationship then I would override the Tuplizer method as follows:




    public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {
        super.afterInitialize(entity, lazyPropertiesAreUnfetched, session);
        // Check to see if the entity is a person 
        if (Person.class.isAssignableFrom(entity.getClass())) {    
            
            // Always provide the true implementation and replace the proxied object
            Person person = (Person) entity;
            Person classMate = (Person) entity.getClassMate();
            if ( classMate != null) {
                classMate = initializeAndUnproxy(classMate); // Fully Initialize the proxy
                person.setClassMate(class); // replace proxy
            }
        }
        
    }



References:

http://techscouting.wordpress.com/2010/09/24/instanceof-fails-with-hibernate-lazy-loading-and-entity-class-hierarchy/

http://stackoverflow.com/questions/2959475/hibernate-lazy-loading-proxy-incompatable-w-other-frameworks

Tuesday, November 9, 2010

SocketException Connection reset on windows 7

While trying to recreate a development environment for a Java Web application on my new laptop with Windows 7, I encountered the dreaded SocketException Connection reset exceptions.

I spent hours overlooking my configuration for the application ensuring that everything was the same as my existing development environment at work but I couldn't find any reasons for the error.

After much investigation and research, I stumbled upon an article where somebody else had experienced similar problems on the Windows 7 OS here:

http://stackoverflow.com/questions/2370388/socketexception-address-incompatible-with-requested-protocol

This gave me the idea that I should probably try disabling support for IPV6
http://support.microsoft.com/kb/929852

After disabling it, I no longer encountered the errors!!

I must admit, so far using windows 7 hasn't had many issues until now. But this has caused me much grief and I'm just relieved to have finally worked it out.

Thursday, November 4, 2010

Hibernate testing for Transient entity

            try {
                Serializable id = session.getIdentifier(entity);
                if (id != null)
                    session.buildLockRequest(LockOptions.NONE).lock(entity);
            } catch (TransientObjectException e) {
                // Entity is a new object, nothing to reattach
            }

Tuesday, November 2, 2010

hibernate constrainviolationexception foreign key constraint

This was due to some test cases creating their own hibrenate sessions and transactions and attempting to save across multiple sessions and multiple transactions.

The fix was to ensure only one session is used across DAO calls.

Monday, November 1, 2010

org.hibernate.LazyInitializationException

 I had configured the OpenSessionInViewFilter as expected and yet I was still encountering this error.
After much debugging and code tracing in hibernate and in spring, it boiled down to the spring class

SessionFactoryUtils requiring the the sessionFactory instance be the same in the DAOs and in the filter.
After dumping out the identity of the session factories using System.identityHashCode() method, I discovered that they were in fact different instances hence the:

"no session or session closed" error message!

Why do I have multiple session factories?
It's because in the web.xml and the spring XML configuration it was read twice!

See the following link for more details

http://forum.springsource.org/showthread.php?t=85782

Once I reconfigured spring to only load each configuration file only once, the error message went away!

ThreadLocal is cool

http://javaboutique.internet.com/tutorials/localdata/

Wednesday, October 13, 2010

Windows 7 Wireless Crash

According to Microsoft:

“This issue tends to occur when you select a Wireless LAN from 5 or more access points. (…) This problem occurs because the message handling for Wireless connection is not fast enough and causes overflow in the message queue,”


Here is the official bug report on Microsoft's website:
http://support.microsoft.com/kb/979244/

However, they don't mention any realy solutions, other than to move your computer away from too many wireless access points. Not a real solution at all.

One user reported in detail the pain he went through and the solution he used to get it working:
http://blogs.techrepublic.com.com/window-on-windows/?p=2342

The solution?
Disable IPv6

Lazy Loading with Java's InvocationHandler

To make the most of performance, we typically don't want to eagerly load everything on a DAO Transfer object. We can use Java's InvocationHandler to proxy method calls. Here's a good read on how to do it:

http://blog.frankel.ch/the-power-of-proxies-in-java

Wednesday, October 6, 2010

AJAX and accessing DIV elements

In Firefox I encountered a strange problem when using AJAX to access DIV elements.
I was using a timer to repetitively access a DIV element as follows:

Javascript:
var statusEl = document.getElementById('status');
alert('statusEl'+statusEl);
HTML:
<div id="status" />


On the first timed interval, firefox has no problem finding the element and the alert identifies it as an HTMLElement object. But upon subsequent timed intervals, the alert begins to report the statusEl as null!! Very strange indeed.

Solution:

The solution ended up being to change from <div id="status" />
to <div id="status"></div>

Tuesday, October 5, 2010

Differentiating objects in Java

Use System.identityHashCode(obj) to differentiate objects in java

Wednesday, September 22, 2010

Use JSTL's "c:out" instead of ${} for display

JSTL has a tag called "c:out" which allows variables to be dumped to the screen. Here is an exmaple:

<c:out value="${aUrl}" />

But many people often ask why not use the less verbose method as follows:

${aUrl}

Although ${} is much simpler, there are many reasons for using c:out instead. One of the main reasons is escaping of HTML characters. If the variable holds a string that contains tags such as
<div> , then the browser will read it as a tag and screw up the layout of your page.

For a list of what gets escaped click here.

Escaping of user input is very important for security reasons. Recently, there has been an article on the net about how Twitter was hacked by "Javascript Injection". Here is one of the articles:

http://blog.trendmicro.com/twitter-mouseover-flaw-allows-script-injection/

Bascially, the problem for Twitter was that they were not escaping user input when displaying links. Had they used something similar to JSTL's c:out tag, then they would have been protected.

Tuesday, September 14, 2010

spring 3 mvc annotation-driven with DWR annotations

I am currently working on a new project that uses Spring 3 MVC Annotation-driven model. I had used DWR on previous projects successfully, but without using annotations, and relying on XML configuration.

After having played around with Spring's annotation driven model, I found it much easier than it's XML counterpart, and so I was determined to get DWR working in the same manner.

mvc-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
    
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
       http://www.directwebremoting.org/schema/spring-dwr
       http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd">


    
    <!-- ================================== DWR configurations ===================================== -->    
    <dwr:configuration>
        <dwr:convert type="bean" class="podd.apn.tab.FacsImportStatus" />    
    </dwr:configuration>
    <dwr:annotation-config />
    <dwr:url-mapping />
    <dwr:controller id="dwrController" debug="true" />    
    
    <!-- Configures the @Controller programming model -->
    <mvc:annotation-driven />

    <!-- Forwards requests to the "/" resource to the "welcome" view -->
    <mvc:view-controller path="/" view-name="welcome"/>
    <!-- 
    <mvc:view-controller path="/*" />
     -->    

    <!-- Configures Handler Interceptors -->    
    <mvc:interceptors>
        <!-- Changes the locale when a 'locale' request parameter is sent; e.g. /?locale=de -->
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
    </mvc:interceptors>

    <!-- Saves a locale change using a cookie -->
    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" />

    <!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>



    

</beans>


web.xml
  <!-- =============
      SERVLETS
   ============  -->
  <servlet>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
                /WEB-INF/spring/app-config.xml
            </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  
    <servlet>
        <servlet-name>uploadServlet</servlet-name>
        <servlet-class>podd.apn.servlet.UploadServlet</servlet-class>
    </servlet>

    <!-- =================
        SERVLET MAPPINGS
     ================  -->
  <servlet-mapping>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <url-pattern>/spring/*</url-pattern>
  </servlet-mapping>
  
  <!--  DWR -->
  <servlet-mapping>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <url-pattern>/dwr/*</url-pattern>
  </servlet-mapping>


And then to verify that it DWR is integrated correctly you can visit:

http://localhost:8989/podd-apn/dwr/engine.js

Referneces:

http://www.codercorp.com/blog/spring/configuring-dwr-30-with-spring-using-annotations.html

Sunday, August 15, 2010

Caused by: java.lang.Error: This version of SLF4J requires log4j version 1.2.12 or later.

I recently synched up to a project to make a new build and upon deployment I encountered a frustrating error:

Caused by: java.lang.Error: This version of SLF4J requires log4j version 1.2.12 or later.

This issue was a real pain, because the error message was very misleading. Basically, the error message is complaining that I don't have a log4j version 1.2.12 or greater.

I checked my classpath, performed a cleaned build, cleared my tomcat cache and restarted tomcat, and none of them fixed the issue. Indeed, my log4j version 1.2.14!!

Bah, I started to dig deeper into the issue and it boiled down to this:

I had replace

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.0</version>
        </dependency>


With:

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.5.6</version>
    </dependency>     
                        
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.5.6</version>
    </dependency>   

I hope this saves somebody else hours of pain

Tuesday, August 10, 2010

Customizing swfupload

After playing around with swfupload, there were a few customizations I needed to make.

1) I wanted to add the files to the user's session.
2) After uploading has completed, by default, swfupload will remove all the items. I wanted to keep the listed items so that the user can review which files were uploaded if they needed to.

Adding to the user session

Since swfupload uses Flash as the underlying mechanism for uploads, the behaviour for executing flash is different for each browser. It turns out Firefox opens a new process and a new cookie for performing the upload as noted in this article:

http://www.thanksmister.com/index.php/archive/firefox-flex-urlrequest-and-sessions-issue/ 

So to work around the issue, the jsessionid was explicity passed into the URL of the upload. With the jsessionid in the URL, Tomcat was able to attach the session to the request.

Here's another article the describes the problem in more detail:
http://blogs.bigfish.tv/adam/2008/04/01/cakephp-12-sessions-and-swfupload/

Below is the code for adding the jsessionid:


function createSwfUpload(fieldName, sessionId,swfUploadUrl, swfButtonUrl, swfButtonPlaceHolderId, swfFlashUrl, progressTarget, buttonCancelId) {
    
    var uploadUrlSession = swfUploadUrl+";jsessionid="+sessionId;
    
    var swfUpload = new SWFUpload({
        
        // The name of the field name that the files are attached to
        file_post_name : fieldName,
        
        // Backend Settings
        upload_url: uploadUrlSession,
        post_params: {"JSESSIONID" : sessionId},

        // File Upload Settings
        file_size_limit : "102400",    // 100MB
        file_types : "*.*",
        file_types_description : "All Files",
        file_upload_limit : "100",
        file_queue_limit : "0",

        // Event Handler Settings (all my handlers are in the Handler.js file)
        file_dialog_start_handler : fileDialogStart,
        file_queued_handler : fileQueued,
        file_queue_error_handler : fileQueueError,
        file_dialog_complete_handler : fileDialogComplete,
        upload_start_handler : uploadStart,
        upload_progress_handler : uploadProgress,
        upload_error_handler : uploadError,
        upload_success_handler : uploadSuccess,
        upload_complete_handler : uploadComplete,

        // Button Settings
        button_image_url : swfButtonUrl,
        button_placeholder_id : swfButtonPlaceHolderId,
        button_width: 61,
        button_height: 22,
        
        // Flash Settings
        flash_url : swfFlashUrl,
        

        custom_settings : {
            progressTarget : progressTarget,
            cancelButtonId : buttonCancelId
        },
        
        // Debug Settings
        debug: false
    });    
    
    return swfUpload;
    
}

Keep list of Uploaded Items

After the upload completes, swfupload automatically hides the progress results. I wanted our users to review which files got uploaded if they needed to. Surprisingly, there was no easy way to configure this. This is what I meant in my other post that swfupload was a bit clunky, but at least it works compared to the "uploadify" alternative. To make the change I commented out some of the code in the fileprogress.js file:

FileProgress.prototype.setError = function () {
    this.fileProgressElement.className = "progressContainer red";
    this.fileProgressElement.childNodes[3].className = "progressBarError";
    this.fileProgressElement.childNodes[3].style.width = "";

    // COMMENT OUT TO STOP REMOVING UPLOAD RESULT
    //var oSelf = this;
    //this.setTimer(setTimeout(function () {
    //    oSelf.disappear();
    //}, 5000));};

Reference: http://www.swfupload.org/forum/generaldiscussion/2123

Multiple file uploads

I've recently been faced with a project where a client needs to be able to upload multiple files in a form submission. I've faced this problem before and there have been many solutions:

One of the older solutions was to expect that the user would ZIP up all the files so that we effectively convert a multiple file problem to a single file. While this did work, it relied on the user to know how to ZIP up files and expect them to perform an extra step of zipping up the files. Not so elegant.

Another solution, is to use a Java applet. The con of using this implementation is that users are expected to have Java already installed on their system. This is a barrier since not all computers will have them installed. The advantage is that once it is installed, then works regardless of what browser is being used.

Flash uploader has recently been popularized by several websites which include Youtube, Flickr and Facebook. Because of this websites, many users will already have flash installed and therefore is less of a barrier. One of the disadvantages is that behaviour of Flash can be different across browsers and different versions of Flash can behave differently as we will soon see.

Many of my users are not very comfortable with using computers, and many of them will only use a computer when they have to. That being said, having to install something on their computer would seem to be a daunting task. Therefore I decided to go with Flash because most people will already have it installed.

At first I went with a utility called "Uploadify" which can be found here:

http://www.uploadify.com/

What I liked about this solution was that it was very elegant and easy to use. But I learned very quickly, that it just didn't work. It was broken for the latest flash version (version 10) and had very little support. It's been noted on their bug list from so many people, but none of the developers acknowledged any plans to fix it.

http://www.uploadify.com/forum/viewtopic.php?f=4&t=5627

I went to look for another solution that was actively being maintained. I stumbled upon "SwfUpload" found here:

http://code.google.com/p/swfupload/

The coding wasn't as elegant as Uploadify, but at least it worked, and it worked across all major browsers. The Javascript coding is a bit clunky, but once you have it up and running, it works great.

For those of you looking at comparing other solutions heres a good reference website:

http://qubit-toolkit.org/wiki/index.php?title=Multiple_file_upload

Wednesday, July 28, 2010

Cygwin: less reports WARNING: terminal is not fully functional

I have been using the "less" command Cygwin without problems for almost a year. For a new project I needed to have perl installed so I downloaed "Strawberry Perl" and installed it.

Afterwards, in cygwin everytime I tried to issue the "less" command it complained that the "terminal is not fully functional".

Turns out Strawberry perl was adding the environment variable TERM with a value of dumb.
Deleting the TERM fixed the issue.

Tuesday, July 27, 2010

inline elements and background-images

This dreaded issue has been looked at to death in so many forums, but in all my research I haven't found a working solution. In here, I wil describe a few solutions that worked for me but let's start with the basics first.

The issue that we're facing be described in detail here: http://www.maxdesign.com.au/articles/inline/

We are attaching a background-image to all elements that have the 'icon' attribute set. The advantage of doing this is that if we wanted to change a commonly used image, we'd only have to change it in one spot. Here's some of the code:


[icon] {
    padding-right: 20px;
    background: no-repeat center right;
}

[icon='required'] {
    background-image: url(../images/required.png);
}
[icon='toggle'] {
    background-image: url(../images/toggle.png);
}
[icon='addField'] {
    background-image: url(../images/add.png);
}
[icon='first'] {
    background-image: url(../images/btn_first.png);
}
[icon='last'] {
    background-image: url(../images/btn_last.png);
}
[icon='next'] {
    background-image: url(../images/btn_next.png);
}
[icon='prev'] {
    background-image: url(../images/btn_prev.png);
}

The image icon is visible in firefox, but not in IE 7. It's not at fault of IE (for once), because inline elements with padding on them has undefined behaviour and the CSS spec gives no details.


[icon] {
    padding-right: 20px;
    background: no-repeat center right;
}

We we're applying the icon attribute to Anchor elements as follows:

<a href="javascript:animatedcollapse.toggle('details')" icon="toggle" title="View Details"></a>


Solutions:

1) Adding a space

I stumbled upon this accidently while trying other possible solutions, and I haven't seen it documented anywhere else so it is worth mentioning. It's quite simple. If we add   inside the anchor element, then IE7 will display the icon correctly. The added side effect is that there will be a space. It works but then that means you have to add a silly   to all your elements.

2) Javascript/jQuery

The idea is to inspect all elements that have the icon attribute, and pull out the URL for the background-image and create a new element and assign the src attribute as follows:
<!--[if IE 7]>
    <script type="text/javascript">
    
        $(document).ready(function() 
        { 
        
            $("a[icon]").each(function() 
                    { 
                var iconUrl = $(this).css("background-image");
                iconUrl = iconUrl.replace(/"/g,"").replace(/url\(|\)$/ig, "");
                
                
                var imgEl = document.createElement('img');
                imgEl.src = iconUrl;
    
                $(this).css('icon','');
                this.removeAttribute("icon");
                
                $(this).append(imgEl);
                $(this).hover();
            }); 
        });
            
    </script>
<![endif]-->

It's not pretty, but if your project is already using jQuery and you have a template page, then you can add this to your template.

3)  Switching the CSS display property
 This is the best solution with the least amount code and less invasive. The idea is to trick IE 7 into using a display property of inline-block but then switching it back inline as follows:

[icon] {
    *display: inline-block;
}
[icon] {
    *display: inline;
    background: no-repeat right center;
    *position: absolute;
    padding-right: 20px;
}

The asteriks are IE 7 specific as mentioned here: http://css-tricks.com/how-to-create-an-ie-only-stylesheet/

maven eclipse:eclipse not adding aspectj jars to classpath

Normally when I want to add new JARs to my classpath in eclipse I execute the following maven command:

mvn eclipse:eclipse

However, when adding aspjectj libraries, the above command did not update my .classpath to inlucde aspectj.
I searched the web and found that I needed to add the following to my pom.xml file:


<!-- To allow aspectj jars be added to the classpath for eclipse-->    
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-eclipse-plugin</artifactId>
                <configuration>
                    <ajdtVersion>none</ajdtVersion>
                </configuration>
            </plugin>

Reference: http://maven.40175.n5.nabble.com/mvn-eclipse-eclipse-aspecjrt-not-added-to-classpath-td120235.html

Thursday, July 22, 2010

Hibernate count on superclass with discriminator

In Hibernate we can use discriminators to subclass from a common class. This is very helpful if we want to map common fields to different tables in the database.

For example, I have an abstract class called Gene. Now all organisms will have Genes, but if we want to differentiate the Gene based on the organism, we subclass Gene to make MouseGene and ZebrafishGene.


In the hibernate O/R mapping file we can have the following:



  <class name="au.edu.apf.phenomebank.strain.Gene" abstract="true" table="genes">
      
          <id name="id" type="java.lang.Long">
            <generator class="increment"/>
        </id>
      
        <!-- DISCRIMINATOR MUST COME IMMEDIATELY AFTER ID ELEMENT. AND SUBCLASS ELEMENTS MUST BE AT THE END !!! -->
        <discriminator column="gene_class" type="string" />      
      
          <property name="geneName" column="affected_gene_name" type="text" />
        <property name="symbol" column="affected_gene_symbol" type="text" />
        <property name="synonyms" type="text" />
        <property name="alleleName" column="allele_name" type="text" />
        <property name="alleleSymbol" column="allele_symbol" type="text" />
        <property name="alleleSynonyms" column="allele_synonyms" type="text" />
        
        <property name="proteinExpression" column="protein_expression" type="au.edu.apf.phenomebank.db.ProteinExpressionUserType" />
        <property name="microsatelliteMarkers" column="microsatellite_markers" type="text" />
        <property name="ensembl" column="ensembl" type="text" />
        <many-to-one name="mutationSequence" column="mutation_sequence_id" cascade="save-update" />
        <property name="geneticAlteration" column="genetic_alteration" type="text" />
        
        <property name="chromosomeLocation" column="chromosome_location" type="text"  />
        <property  name="locationOnChr" column="location_on_chr" type="text" />
        
        <!-- ALL SUBCLASS ELEMENTS MUST BE AFTER PROPERTY ELEMENTS. ORDERING IS VERY IMPORTANT !!! --> 
        <subclass name="au.edu.apf.phenomebank.db.mouse.MouseGene" discriminator-value="mouse">
            <property name="mgiGeneAccessionId" column="MGI_gene_accession_id" type="text" />
            <property name="mgiGeneAccessionIdUrl" column="MGI_gene_accession_id_url" type="text" />
            <property name="mgiAlleleAccessionId" column="MGI_allele_accession_id" type="text" />
            <property name="mgiAlleleAccessionIdUrl" column="MGI_allele_accession_id_url" type="text" />    
        </subclass>         
        
  </class>


  <class name="au.edu.apf.phenomebank.strain.ZebrafishGene" table="zebrafish_genes">
      
          <id name="id" type="java.lang.Long">
            <generator class="increment"/>
        </id>
      
        <!-- DISCRIMINATOR MUST COME IMMEDIATELY AFTER ID ELEMENT. AND SUBCLASS ELEMENTS MUST BE AT THE END !!! -->
        <discriminator column="gene_class" type="string" />      
      
          <property name="geneName" column="affected_gene_name" type="text" />
        <property name="symbol" column="affected_gene_symbol" type="text" />
        <property name="synonyms" type="text" />
        <property name="alleleName" column="allele_name" type="text" />
        <property name="alleleSymbol" column="allele_symbol" type="text" />
        <property name="alleleSynonyms" column="allele_synonyms" type="text" />
        
        <property name="proteinExpression" column="protein_expression" type="au.edu.apf.phenomebank.db.ProteinExpressionUserType" />
        <property name="microsatelliteMarkers" column="microsatellite_markers" type="text" />
        <property name="ensembl" column="ensembl" type="text" />
        <many-to-one name="mutationSequence" column="mutation_sequence_id" cascade="save-update" />
        <property name="geneticAlteration" column="genetic_alteration" type="text" />
        
        <property name="chromosomeLocation" column="chromosome_location" type="text"  />
        <property  name="locationOnChr" column="location_on_chr" type="text" />
        
        <!-- ALL SUBCLASS ELEMENTS MUST BE AFTER PROPERTY ELEMENTS. ORDERING IS VERY IMPORTANT !!! --> 
        <subclass name="au.edu.apf.phenomebank.db.zebrafish.ZebrafishGene" discriminator-value="zebrafish">
            <property name="zebrafishProperty" column="MGI_gene_accession_id" type="text" />
        </subclass>         
        
  </class>    




Now in Hibernate, if you performed a count using the following HQL call:
String sql = "SELECT COUNT(DISTINCT g.geneName) FROM "+Gene.class.getSimpleName()+ " g"; 
List list = getHibernateTemplate().find(sql); 

This will actually return a count of all the distinct gene names from both MouseGene table and Zebrafish Gene table where each column of the returned result represents a count from each table. This is because we are searching based on the abstract class Gene, and Hibernate is smart enough to search all subclasses.

Now if you want to only search on the one table then you have to specify the subclass as follows:


String sql = "SELECT COUNT(DISTINCT g.geneName) FROM "+MouseGene.class.getSimpleName()+ " g"; 

Thursday, June 10, 2010

jQuery calendar IE 7



I was trying to use the jQuery calendar datepicker (http://docs.jquery.com/UI/Datepicker) and I've had it working before on another project (on all browsers including IE 7), but in the current project I'm working on, sometimes the arrows (Next, prev) to move to the next and previous month don't work correctly in IE7. In firefox, opera, safari, IE8 it works fine. What's worse, it also worked fine in IE 7 on the previous project. So how was this project different?

I had noticed that the global CSS property position was set to relative as follows:

* {
    position: relative;
}

 To get it working, I did an override on the global property as follows:
* {
    position: static;
}

That got the arrows in the calendars working again

Monday, June 7, 2010

HibernateException "The class has no identifier property"

I got the above error when updating an existing record loaded from the database and not when inserting new records.

The hbm.xml file showed the following:


        <id column="user_id" type="java.lang.Long">
            <generator class="foreign">
                <param name="property">user</param>
            </generator>
        </id>

I added the name attribute in the id element, and that resolved the issue:


        <id name="id" column="user_id" type="java.lang.Long">
            <generator class="foreign">
                <param name="property">user</param>
            </generator>
        </id>

Wednesday, May 5, 2010

Solr Highlighting

I have used Lucene a few years ago when highlighting was not even feature. Now I am using Solr to perform my searches and highlighting is very much something we would like to use. At first, it was not very clear how to get it working and nor are the docs very helpful. So I've written up a short blurb on what was needed.

If you've configured your schema correctly where the fields to be highlighted must have "stored=true", then most of the work is in your constructed query. You need to add the following to your query:

  • hl=true
  • hl.fl=*
Here is an example query:

http://localhost:8989/solr/select?q=britta&hl=true&hl.fl=*

And an example response might be:

<response>
−
<lst name="responseHeader">
<int name="status">0</int>
<int name="QTime">8</int>
−
<lst name="params">
<str name="q">britta</str>
<str name="hl.fl">*</str>
<str name="hl">true</str>
</lst>
</lst>
−
<result name="response" numFound="1" start="0">
−
<doc>
<str name="description">britta is awesome</str>
<str name="id">poddObject:67</str>
</doc>
</result>
−
<lst name="highlighting">
−
<lst name="poddObject:67">
−
<arr name="description">
<str><em>britta</em> is awesome</str>
</arr>
</lst>
</lst>
</response>


If it's still not working for you, here is another reference that provides additional things you should look for:
http://www.mail-archive.com/solr-user@lucene.apache.org/msg11031.html

Phil

Tuesday, May 4, 2010

Loading configuration file from Classpath

InputStream is = getClass().getClassLoader().getResourceAsStream(INDEX_CONFIG_FILE);

Thursday, April 29, 2010

JUnit Hibernate Lazy initialization

To configure your JUnit testcases for testing data access through Hibernate with entity mappings using lazy initialization requires minor changes to the setUp() and tearDown() methods as follows:


    /**
     * The application context used in this test case.
     */
    protected ApplicationContext ctx;
    protected StrainDao dao;
    // keep reference to session factory to handle lazy-initialization
    protected SessionFactory sessionFactory;
    protected Session session;
    
    public PhenomeBankTestCase(final String name) {
        super(name);

        // Override the default definition for dataSource
        /*
        final String[] files = {                    
            "file:C:/workspace/mouse/src/main/webapp/WEB-INF/applicationContext-hibernate.xml",
            "classpath:applicationContextDataSource.xml",
            "file:C:/workspace/mouse/src/main/webapp/WEB-INF/phenomeBank-service.xml",             
        };*/
        
        final String[] files = {                    
                "file:./src/main/webapp/WEB-INF/applicationContext-hibernate.xml",
                "classpath:applicationContextDataSource.xml",
                "file:./src/main/webapp/WEB-INF/phenomeBank-service.xml",             
            };        

        ctx = new ClassPathXmlApplicationContext(files);
        sessionFactory = (SessionFactory)ctx.getBean(BEAN_ID_SESSION_FACTORY);
    }
    
    /**
     * Sets up the test fixture.
     */
    @Override
    public void setUp() {
        dao = (StrainDao) ctx.getBean(BEAN_ID_STRAIN_DAO);         

        session = SessionFactoryUtils.getSession(this.sessionFactory, true);
        TransactionSynchronizationManager.bindResource(this.sessionFactory, new SessionHolder(session));        
    }

    @Override
    protected void tearDown() throws Exception {
        TransactionSynchronizationManager.unbindResource(this.sessionFactory);
        SessionFactoryUtils.releaseSession(this.session, this.sessionFactory);
    }



Reference: http://note19.com/2007/08/26/lazy-initialization-with-hibernate-and-spring/

Wednesday, April 28, 2010

Hudson and missing maven repository artifacts

When attempting to make a build in Hudson for the first time, it complained of missing artifacts in the maven repo. I found that I had to configure the MAVEN_HOME/conf/settings.xml file to point to the maven repo by editing the localRepository element

Here's a reference for more details:
http://stackoverflow.com/questions/44144/hudson-cant-build-my-maven-2-project-because-it-says-artifacts-are-missing-from

Once the initial build was working, I had to make additional changes to make maven do a 'clean package'
and perform a build everytime a change gets submitted to SVN as shown below:

Tuesday, April 27, 2010

SFTP: Received message too long 1936094320

The problem:

Recently the server running SFTP was updated with some security patches applied. Soon afterwards, one of the users couldn't connect via SFTP with the following error:


$ sftp broken_user@server

Received message too long 1936094320


 I spent quite a bit of time searching for solutions and most talked about an echo statement in one of the .bashrc or .bash_profile scripts. However, upon inspection I couldn't find any echo statements.

However, I noticed that when I used the root user it worked fine:


$ sftp root@server 

 The solution:

I did manage to find a workaround, although I am still unable to explain why it works.
I ended up editing the /etc/passwd file and changed a line from:


broken_user:x:503:503::/var/websites/my_website/./:/bin/sftpsh

to

broken_user:x:503:503::/var/websites/my_website/./:/bin/bash

Thursday, April 8, 2010

Extending an existing Web application WAR

Problem:

Extend an existing web application, reusing as much as possible including not just the source code, but the web resources such as JSPs, images, CSS styling, Javascript etc...

The simple way would be to branch or copy the existing application and import it into a new project, but this has a major drawback. What if there are bug fixes or changes made to the base web application? If we were to branch, then that would mean having to merge all the changes from the base web application with the new web application! I say GAH!

Solution:

If you're already using Maven as your build, then it's Maven WAR overlays to the rescue!

An article about Maven WAR overlays can be found here:
Reference: http://maven.apache.org/plugins/maven-war-plugin/examples/war-overlay.html

To automatically include all dependencies from the base WAR, I use the warpath plugin found here:
http://static.appfuse.org/maven-warpath-plugin/usage.html

You are effectively creating a WAR project that has a dependency on the base WAR project found in your maven repo. Thus, any changes made to the base WAR application can easily be picked up by simply synching up with your SVN code base and rebuilding your new WAR.

In your new web app project, when you make a build, maven will automatically merge the 2 WAR files (base WAR and new app WAR) together to create a new WAR file.

Below is a sample of the pom.xml file to enable this merging:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>au.org.australianphenomics</groupId>
  <artifactId>podd-apn-webapp</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>podd-apn-webapp</name>
  <url>http://maven.apache.org</url>
  
  <developers>
      <developer>
          <name>Philip Wu</name>
          <email>philip.wu@anu.edu.au</email>
      </developer>
  </developers>  
  

  
  
  <!-- ================ 
      Build 
   ==================== -->  
  <build>
      <finalName>podd-apn</finalName>
    <plugins>
         
     
        <plugin>
          <groupId>org.appfuse</groupId>
          <artifactId>maven-warpath-plugin</artifactId>
          <version>2.0.2</version>
          <extensions>true</extensions>
          <executions>
            <execution>
              <goals>
                <goal>add-classes</goal>
              </goals>
            </execution>
          </executions>
        </plugin>     
     
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.0</version>
            <configuration>           
                <dependentWarIncludes>**</dependentWarIncludes>   
            </configuration>
        </plugin>
        
    </plugins>  
         
    
  </build>
  
  <!-- ================ 
      Dependencies  
   ==================== -->  

      <dependencies>
       
        <dependency>
            <groupId>au.edu.uq.itee.maenad</groupId>
            <artifactId>podd-webapp</artifactId>
            <version>1.0</version>     
            <type>war</type>
        </dependency>
     
        <dependency>
            <groupId>au.edu.uq.itee.maenad</groupId>
            <artifactId>podd-webapp</artifactId>
            <version>1.0</version> 
            <type>warpath</type>        
        </dependency>          
  
    </dependencies>

  
  
  
  
</project>

As an 'Overlay' the web.xml files from the two WARs are not merged.
If you're looking to do just that, then you might want to take a look at:
http://cargo.codehaus.org/Merging+WAR+files

Monday, April 5, 2010

Java String.trim() not trimming Whitespace!

The problem:

I was using String.trim() to remove leading and trailing whitespace characters from an imported string.
However it turns out, that the trim() method only checks for a whitespace characters defined in ASCII.
That is, any non-ASCII whitespace characters will still persist!

Reference: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4080617

Diagnosis:

Upon inspecting each character of the string, the whitespace character returned a value of 160
The code to inspect is below:
        for (int i=0; i < string160.length(); i++) {                    
            char c = string160.charAt(i);
            int intC = (int) c;
            System.out.println(intC);            
        }


Solution:

The solution was to remove all instances of this troublesome character with the following code:

string160 = string160.replaceAll("[\\u00A0]", "");

Thursday, March 25, 2010

Constructing table views with Hibernate

Database views are convenient to use especially for a view that represents a complex query or one that is used repetitively.

Here I will show you how to construct a database view using Hibernate.

In the HBM mapping file you can declare your view using the element subselect.
The SQL used should be native to the database you are using and should not be HQL.

You use the synchronize elements to identify which tables the SQL query uses to construct the view.

Below is an example:

   <!-- VIEW -->
    <class name="au.edu.apf.phenomebank.report.inventory.mouse.StrainCryo" >
        <!-- Postgres specific SQL call -->
        <subselect>
            SELECT '' || cs.id || s.id  AS id, s.id AS strain_id, cs.id AS cryosession_id 
            FROM cryo_session cs 
            JOIN cryo_session_result csr ON(cs.id=csr.cryo_session_id) 
            JOIN mouse m ON (csr.mouse_id=m.id) 
            JOIN strains s ON (m.strain_id=s.id) 
            GROUP BY cs.date_of_session, s.id, cs.id 
            ORDER BY cs.date_of_session
        </subselect>
        <synchronize table="cryo_session"/>        
        <synchronize table="cryo_session_result"/>
        <synchronize table="mouse"/>
        <synchronize table="strains"/>
        
        <id name="id" type="java.lang.Long" />

                
        <many-to-one name="strain" column="strain_id" cascade="none" not-null="true" />
        <many-to-one name="cryoSession" column="cryosession_id" cascade="none" not-null="true" />
        
    </class>

I combine two foreign key ID's to construct a unique key for the table view as follows:
'' || cs.id || s.id


The entity representing the view is a simple POJO as follows:

public class StrainCryo {

    /**
     * Arbitrary ID to create the view in Hibernate
     */
    private Long id;
    private Strain strain;
    private CryoSession cryoSession;
    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public Strain getStrain() {
        return strain;
    }
    public void setStrain(Strain strain) {
        this.strain = strain;
    }
    public CryoSession getCryoSession() {
        return cryoSession;
    }
    public void setCryoSession(CryoSession cryoSession) {
        this.cryoSession = cryoSession;
    }
    
    
    
}

Monday, March 15, 2010

Externalizing configuration properties

Generally, for deployment specific configurations we would like to move them out of spring specific configuration files and into a properties file.The purpose of the bean-wiring file is to define the relationships between dependent objects, and should not be used to define deployment configurations.

I've come across 2 ways to Externalize configuration properties and it really depends on the technologies you have at your disposal.

They both acheive the same result of externalizing configuration properties, except that Maven has the added benefit of using Profiles to select an appropriate build. For example, you can have one profile for creating a test build and another profile for a production build.

Preferrably, I like to use the Maven Resource filtering strategy, because it allows you to easily create a different build depending on the type of deployment you'd like to use based on Maven Profiles. Here's a good quote describing Maven resource filtering:

You can use Maven to perform variable replacement on project resources. When resource filtering is activated, Maven will scan resources for references to Maven property references surrounded by ${ and }. When it finds these references it will replace them with the appropriate value in much the same way the properties defined in the previous section can be referenced from a POM. This feature is especially helpful when you need to parameterize a build with different configuration values depending on the target deployment platform.

Sunday, February 14, 2010

Why isn't my datasource configuration being picked up in Tomcat 6?

I had an unusual problem with Tomcat 6 where changes to my database configuration stored in the /META-INF/context.xml file was not being picked up upon server restart or application reload.


Below is a sample:

<!-- antiResourceLocking="true" -->
<Context path="/phenbank"
         reloadable="true"
         
         >

  <Resource name="jdbc/phenomebank"              
            type="javax.sql.DataSource" username="" password=""
            driverClassName="org.postgresql.Driver" 
            url="jdbc:postgresql://localhost:5432/phenomebank"
            maxActive="8" maxIdle="4"
            global="jdbc/phenomebank" 
            />

               
</Context>

When I had changed the database name from 'phenomebank' to something else like 'newdatabase', the log files continued to show that it was trying to connect to 'phenomebank' instead of 'newdatabase'

It turns out that Tomcat 6 was caching my configuration file in a separate directory, such that application reload and server restart would not automatically pick up the new configuration!!

The solution was to delete the cached files in Tomcat 6 found in this folder:

C:\apache-tomcat-6.0.20\conf\Catalina

To prevent Tomcat from caching the configuration again you can edit an attribute called cachingAllowed in your context.xml as follows:

<Context path="/zebrafish"
         reloadable="true"
         cachingAllowed="false"         >

Thursday, January 28, 2010

No binding factory for namespace http://schemas.xmlsoap.org/wsdl/soap/ registered

The error is misleading:

The spring configuration file for CXF is missing some imports:

    <import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-http.xml" />

Wednesday, January 27, 2010

Gah! Ontology Lookup Service fails against it's own Schema!!

There is a Ontology lookup service available here:

http://www.ebi.ac.uk/ontology-lookup/

Having a central repository of Ontologies is great idea and I give them kudos for all the hard work.
They advertise a web service  for looking up various Ontologies using the SOAP protocol, which can be found here:

http://www.ebi.ac.uk/ontology-lookup/WSDLDocumentation.do#Link0332BDE0

However, as of today, they have issues with their web service.
I used the wsdl2java utility found with Apache CXF and that generated the stub code successfully.
Using the stub code I threw together some client code to invoke a service. An example is shown below:

package au.edu.apf.phenomebank.ontology;



import java.util.List;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.xml.xml_soap.Map;
import org.apache.xml.xml_soap.MapItem;

import uk.ac.ebi.ontology_lookup.ontologyquery.Query;
import uk.ac.ebi.ontology_lookup.ontologyquery.QueryService;

public class OLSTest {

    public static void main (String[] args) {
        
        
        QueryService ss = new QueryService();
        

        Query ontQuery = ss.getOntologyQuery();
        
        Client client = ClientProxy.getClient(ontQuery);
        client.getInInterceptors().add(new LoggingInInterceptor());
        //client.getInInterceptors().add(new FixInterceptor());
        client.getOutInterceptors().add(new LoggingOutInterceptor());
        
        
        
        System.out.println("Getting ontology names");
        Map ontologyNames =  ontQuery.getOntologyNames();
        
        
        List<MapItem> mapItems = ontologyNames.getItem();
        for (MapItem mapItem : mapItems) {
            Object mapValue = mapItem.getValue();
            System.out.println("mapValue="+mapValue);
        }
    }
    
}

The errors started to happen when I invoked a service call on the stub API:
ontQuery.getOntologyNames();

The following errors were dumped in Eclipse:
DefaultValidationEventHandler: [ERROR]: unexpected element (uri:"", local:"item"). Expected elements are <{http://xml.apache.org/xml-soap}item> 
     Location: line 1
28/01/2010 5:09:52 PM org.apache.cxf.phase.PhaseInterceptorChain doIntercept
WARNING: Interceptor has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Unmarshalling Error: unexpected element (uri:"", local:"item"). Expected elements are <{http://xml.apache.org/xml-soap}item> 

Bascially, it's complaning that the <item>> element is missing the namespace of
http://xml.apache.org/xml-soap 

To verify was wrong I needed to look at the actual SOAP message being sent to me:

  <?xml version="1.0" encoding="UTF-8" ?> 
- <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <soapenv:Body>
- <getOntologyNamesResponse xmlns="http://www.ebi.ac.uk/ontology-lookup/OntologyQuery">
- <getOntologyNamesReturn>
- <item xmlns:ns1="http://xml.apache.org/xml-soap" xmlns="">
  <key xsi:type="xsd:string">LSM</key> 
  <value xsi:type="xsd:string">Leukocyte Surface Markers</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">TADS</key> 
  <value xsi:type="xsd:string">Tick Gross Anatomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">FBsp</key> 
  <value xsi:type="xsd:string">Fly taxonomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">FIX</key> 
  <value xsi:type="xsd:string">Physico-Chemical Methods and Properties</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">HOM</key> 
  <value xsi:type="xsd:string">Homology Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">SPD</key> 
  <value xsi:type="xsd:string">Spider Comparative Biology Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">RO</key> 
  <value xsi:type="xsd:string">Multiple Alignment</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">HP</key> 
  <value xsi:type="xsd:string">Human phenotype ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">MOD</key> 
  <value xsi:type="xsd:string">Protein Modifications (PSI-MOD)</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">BTO</key> 
  <value xsi:type="xsd:string">BRENDA tissue / enzyme source</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">MFO</key> 
  <value xsi:type="xsd:string">Medaka Fish Anatomy and Development</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">TTO</key> 
  <value xsi:type="xsd:string">Teleost taxonomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">WBls</key> 
  <value xsi:type="xsd:string">C. elegans Development</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">APO</key> 
  <value xsi:type="xsd:string">Yeast phenotypes</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">MAT</key> 
  <value xsi:type="xsd:string">Minimal Information About Anatomy ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">NEWT</key> 
  <value xsi:type="xsd:string">NEWT UniProt Taxonomy Database</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">MI</key> 
  <value xsi:type="xsd:string">Molecular Interaction (PSI MI 2.5)</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">FAO</key> 
  <value xsi:type="xsd:string">Fungal Gross Anatomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">TAIR</key> 
  <value xsi:type="xsd:string">Arabidopsis Development</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">IDO</key> 
  <value xsi:type="xsd:string">Infectious Disease Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">EMAP</key> 
  <value xsi:type="xsd:string">Mouse Gross Anatomy and Development</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">AAO</key> 
  <value xsi:type="xsd:string">Amphibian Gross Anatomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">PRO</key> 
  <value xsi:type="xsd:string">Protein Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">OBO_REL</key> 
  <value xsi:type="xsd:string">OBO Relationship Types</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">ZFA</key> 
  <value xsi:type="xsd:string">Zebrafish Anatomy and Development</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">MA</key> 
  <value xsi:type="xsd:string">Mouse Adult Gross Anatomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">XAO</key> 
  <value xsi:type="xsd:string">Xenopus anatomy and development</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">TRANS</key> 
  <value xsi:type="xsd:string">Pathogen transmission</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">PATO</key> 
  <value xsi:type="xsd:string">Phenotypic qualities (properties)</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">TGMA</key> 
  <value xsi:type="xsd:string">Mosquito Gross Anatomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">PRIDE</key> 
  <value xsi:type="xsd:string">PRIDE Controlled Vocabulary</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">REX</key> 
  <value xsi:type="xsd:string">Physico-Chemical Process</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">UO</key> 
  <value xsi:type="xsd:string">Unit Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">CARO</key> 
  <value xsi:type="xsd:string">Common Anatomy Reference Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">SEP</key> 
  <value xsi:type="xsd:string">Separation Methods</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">TAO</key> 
  <value xsi:type="xsd:string">Teleost Anatomy and Development Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">MP</key> 
  <value xsi:type="xsd:string">Mammalian Phenotype</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">EV</key> 
  <value xsi:type="xsd:string">eVOC (Expressed Sequence Annotation for Humans)</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">FBdv</key> 
  <value xsi:type="xsd:string">Drosophila Development</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">HAO</key> 
  <value xsi:type="xsd:string">Hymenoptera Anatomy Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">MS</key> 
  <value xsi:type="xsd:string">PSI Mass Spectrometry Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">GRO</key> 
  <value xsi:type="xsd:string">Cereal Plant Development</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">EO</key> 
  <value xsi:type="xsd:string">Plant Environmental Conditions</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">PAR</key> 
  <value xsi:type="xsd:string">Protein Affinity Reagents</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">IMR</key> 
  <value xsi:type="xsd:string">Molecule Role (INOH)</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">PSI</key> 
  <value xsi:type="xsd:string">Mass Spectroscopy CV (PSI-MS)</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">PW</key> 
  <value xsi:type="xsd:string">Pathway Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">IEV</key> 
  <value xsi:type="xsd:string">Event (INOH)</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">ECO</key> 
  <value xsi:type="xsd:string">Evidence Codes</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">MIAA</key> 
  <value xsi:type="xsd:string">Minimal Information About Anatomy ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">ENVO</key> 
  <value xsi:type="xsd:string">Environmental Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">BS</key> 
  <value xsi:type="xsd:string">Biosapiens Annotations</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">CCO</key> 
  <value xsi:type="xsd:string">Cell Cycle Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">TO</key> 
  <value xsi:type="xsd:string">Cereal Plant Trait</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">FBcv</key> 
  <value xsi:type="xsd:string">Flybase Controlled Vocabulary</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">MIRO</key> 
  <value xsi:type="xsd:string">Mosquito Insecticide Resistance</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">WBPhenotype</key> 
  <value xsi:type="xsd:string">C. elegans phenotype</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">CHEBI</key> 
  <value xsi:type="xsd:string">Chemical Entities of Biological Interest</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">DOID</key> 
  <value xsi:type="xsd:string">Human Disease</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">BSPO</key> 
  <value xsi:type="xsd:string">Spatial Reference Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">ZDB</key> 
  <value xsi:type="xsd:string">Zebrafish Anatomy and Development</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">WBbt</key> 
  <value xsi:type="xsd:string">C. elegans gross anatomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">FBbi</key> 
  <value xsi:type="xsd:string">Biological Imaging Methods</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">ATO</key> 
  <value xsi:type="xsd:string">Amphibian Taxonomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">FBbt</key> 
  <value xsi:type="xsd:string">Drosophila Gross Anatomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">SO</key> 
  <value xsi:type="xsd:string">Sequence Types and Features</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">FMA</key> 
  <value xsi:type="xsd:string">Foundational Model of Anatomy Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">EHDA</key> 
  <value xsi:type="xsd:string">Human Developmental Anatomy, timed version</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">ZEA</key> 
  <value xsi:type="xsd:string">Maize Gross Anatomy</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">PM</key> 
  <value xsi:type="xsd:string">Phenotypic manifestation (genetic context)</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">PO</key> 
  <value xsi:type="xsd:string">Plant Ontology (Structure, Growth and Developmental Stage)</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">EFO</key> 
  <value xsi:type="xsd:string">ArrayExpress Experimental Factor Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">GO</key> 
  <value xsi:type="xsd:string">Gene Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">ENA</key> 
  <value xsi:type="xsd:string">European Nucleotide Archive Submission Ontology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">MPATH</key> 
  <value xsi:type="xsd:string">Mouse Pathology</value> 
  </item>
- <item xmlns="">
  <key xsi:type="xsd:string">CL</key> 
  <value xsi:type="xsd:string">Cell Type</value> 
  </item>
  </getOntologyNamesReturn>
  </getOntologyNamesResponse>
  </soapenv:Body>
  </soapenv:Envelope>


The main problem is that nearly all the<item> elements don't have a declared namespace. Here's an example:


<item xmlns="">
  <key xsi:type="xsd:string">HOM</key> 
  <value xsi:type="xsd:string">Homology Ontology</value> 
  </item>

And yet in the WSDL file the schema requires that the namespaces be fully qualified:

  <schema elementFormDefault="qualified" targetNamespace="http://xml.apache.org/xml-soap" xmlns="http://www.w3.org/2001/XMLSchema">
   <import namespace="http://model.web.ook.ebi.ac.uk"/>
   <complexType name="mapItem">
    <sequence>
     <element name="key" nillable="true" type="xsd:anyType"/>
     <element name="value" nillable="true" type="xsd:anyType"/>
    </sequence>
   </complexType>
   <complexType name="Map">
    <sequence>
     <element maxOccurs="unbounded" minOccurs="0" name="item" type="apachesoap:mapItem"/>
    </sequence>
   </complexType>
   <complexType name="Vector">
    <sequence>
     <element maxOccurs="unbounded" minOccurs="0" name="item" type="xsd:anyType"/>
    </sequence>
   </complexType>
  </schema>

The workaround for this problem was to download the WSDL file and manually change it from qualified to unqualified as follows:



  <schema elementFormDefault="unqualified" targetNamespace="http://xml.apache.org/xml-soap" xmlns="http://www.w3.org/2001/XMLSchema">
   <import namespace="http://model.web.ook.ebi.ac.uk"/>
   <complexType name="mapItem">
    <sequence>
     <element name="key" nillable="true" type="xsd:anyType"/>
     <element name="value" nillable="true" type="xsd:anyType"/>
    </sequence>
   </complexType>
   <complexType name="Map">
    <sequence>
     <element maxOccurs="unbounded" minOccurs="0" name="item" type="apachesoap:mapItem"/>
    </sequence>
   </complexType>
   <complexType name="Vector">
    <sequence>
     <element maxOccurs="unbounded" minOccurs="0" name="item" type="xsd:anyType"/>
    </sequence>
   </complexType>
  </schema>


More details about this issue can be followed up here:

http://code.google.com/p/ols-ebi/issues/detail?id=6

Hope this helps somebody from the headaches i had to go through to get this working!!