Looking for software experts?
Need an expert advice on software development? Need consulting work done in time and at high standards? Tremend has the right solution for you.

We can provide expertise in:
  •    » high traffic and complex content website infrastructures using Java, PHP or .NET. More here ...
  •    » mobile applications for iPhone, Android or J2ME. More here ...

For an enquiry, send an email to contact [at] tremend [dot] ro.

Problem when adding elements to a TreeSet<Comparator> – some elements are not added

May 17th, 2007 by spostelnicu in Java, General

I thought of sharing with you this little problem that I encountered when using a TreeSet to display an ordered list of items:

I have some items stored in the database, each of them having a unique id.

Some of the items have the same values, only the ids are different.

I also have a business method that creates a list of items, sorted by some custom ordering of fields.

To sort them, I used the following lines of code:

SortedSet result = new TreeSet(itemsComparator);
for (Item item : someItems) {
    if (itemIsEligible(item)) {
        result.add(item);
    }
}

where itemsComparator is an instance of this class:

public class ItemsComparator implements Comparator {
    /**
     * Compare two items for order.
     * @param item1 the first item
     * @param item2 the second item
     * @return -1 if item1 should appear before item2,
               1 if item2 should appear before item1,
               or 0 if the order is not important
     */
    public int compare(Item item1, Item item2) {
        // Sort by field1 descending
        int compareField1 = item1.getField1().compareTo(item2.getField1());
        if (compareField1 != 0) {
            return -compareField1;
        }
        // For equal field1, sort by field2 ascending
        int compareField2 = item1.getField2().compareTo(item2.getField2());
        return compareField2;
    }
}

At some moment I discovered the following bug: if two items had the same values, but different ids, only the last one of them appeared in the result.

After a little debugging I discovered that the problem was this:

TreeSet uses internally a TreeMap to store the elements.

TreeMap uses compareTo to determine the order of the elements, to know where to place them in the internal tree.

And if two elements are different but compareTo returns 0, then TreeMap will consider them equal, and the newly added element replaces the old one.

My solution to this problem was the following:

public class ItemsComparator implements Comparator {
    /**
     * Compare two items for order.
     * To ensure that two different items are not treated as equal,
     * our method will never return 0 for different items!
     * @param item1 the first item
     * @param item2 the second item
     * @return -1 if item1 should appear before item2,
                    1 if item2 should appear before item1,
                    0 if item1 and item2 are the same
     */
    public int compare(Item item1, Item item2) {
        // Sort by field1 descending
        int compareField1 = item1.getField1().compareTo(item2.getField1());
        if (compareField1 != 0) {
            return -compareField1;
        }
        // For equal field1, sort by field2 ascending
        int compareField2 = item1.getField2().compareTo(item2.getField2());
        if (compareField2 != 0) {
            return compareField2;
        }
        // For equal field1 and field1, sort by item id
        return item1.getId().compareTo(item2.getId());
    }
}


technorati tags:, ,

read more ...

Migrate Lucene annotations 3.2.1GA to Hibernate Search 3.0.0.Beta1: object removal

May 9th, 2007 by Ioan Cocan in Java, General

Changes in Hibernate Search are quite frequent, as it is in continued development. Today I found myself looking into a problem generated by migration from Hibernate-Lucene integration in 3.2.1.GA to the new Hibernate Search 3.0.0.Beta1.

The problem: deletion of an object in Hibernate will not trigger the removal from the Lucene index.

First, check the event listener: using a custom implementation I can see the onPostDelete method is called correctly. Still, no deletion from index and no error message either. Looking in the Hibernate Search sources I can see that the deletion uses the DocumentId marker in order to identify the field used for deletion. The old @Keyword(id=true) is deprecated and seems it no longer works.

The solution: Change the annotation from @Keyword(id=true) to @DocumentId. This will help Hibernate search do its magic.

read more ...

Error reading tld listeners java.lang.NullPointerException

May 9th, 2007 by Marius Hanganu in Java, General

I’ve been bugged by this problem for some time now, so I decided investigating a bit. The error shows up when tomcat is trying to reload the web application.


The full stacktrace is shown below:


SEVERE: Error reading tld listeners java.lang.NullPointerException
java.lang.NullPointerException
at org.apache.log4j.Category.isEnabledFor(Category.java:746)
at org.apache.commons.logging.impl.Log4JLogger.isTraceEnabled(Log4JLogger.java:327)
at org.apache.catalina.startup.TldConfig.tldScanResourcePaths(TldConfig.java:582)
at org.apache.catalina.startup.TldConfig.execute(TldConfig.java:283)
at org.apache.catalina.core.StandardContext.processTlds(StandardContext.java:4307)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4144)
at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3025)
at org.apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.java:432)
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1278)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1570)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1579)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1579)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1559)
at java.lang.Thread.run(Thread.java:595)



The solution is quite simple: replace commons-logging.jar from your 1.1 version to a previous version (1.0.4). That’s it. The problem has been discussed here.

technorati tags:, , , ,

read more ...

Handling DWR responses

May 7th, 2007 by Marius Hanganu in Java, General

Seeing this thread on DWR mailing list, I though I’d post one way to deal with DWR response. The actual problem was initiated by someone asking what’s the best way to display status messages to users using DWR.

Lance Semmens describes a solution using a template like:

public class Result<T> {

    private boolean success;

    private T successObject;

    private Map<String,List<String,String>> messages;



    // getters and setters

}


The object obviously needs a DWR converter so that it can be converted to javascript. When an instance of this class gets returned to the js code, the function must check if the operation has been successful and display any errors included in the Result object.

The problem with this approach is that every javascript function used as a DWR callback needs to have the same piece of code:

if(!obj.success) {

    // display error messages

}

When maintaining a large number of DWR callbacks, maintaining the same code in all DWR callbacks is obviously not a choice. Wouldn’t it be useful to have some sort of AOP interceptors for every js callback, dealing with the error messages in an unified and transparent manner?

For this, I’d suggest using something similar to dojo’s event system to intercept all callbacks and handle success cases in an unified manner. If you don’t use dojo, here’s some sample code to intercept all dwr callbacks (more specifically – all methods prefixed with “dwr”).

<html>

<head>

   <script>

       dwrCallback1 = function(response) {

           alert(“fn1: further processing … (” + response.success + “)”);

       }



       dwrCallback2 = function(response) {

           alert(“fn2: further processing … (” + response.success + “)”);

       }



       dwrCallback3 = function(response) {

           alert(“fn3: further processing … (” + response.success + “)”);

       }



       init = function() {

           var m = getMethodsWithPrefixForObject(window, “dwr”);

           for (var i = 0; i < m.length; i++) {

               attachHandlerBefore(window, m[i]);

           }

       }



       attachHandlerBefore = function(obj, methodName) {

           obj["_" + methodName] = obj[methodName];

           obj[methodName] = function(response) {

               if (response.success) {

                   alert(response.msg);

               }

               obj["_" + methodName](response);

           }

       };



       getMethodsWithPrefixForObject = function(obj, prefix) {

           var methods = [];

           if (typeof obj == “object”) {

               for (var prop in obj) {

                   var tmpObj = obj[prop];

                   if (tmpObj == null || typeof tmpObj == “function”) {

                       if (prop.indexOf(prefix) == 0) {

                           methods[methods.length] = prop;

                       }

                   }

               }

           }



           return methods;

       };

   </script>

</head>

<body onload=”init()”>

<button type=”button” onclick=”dwrCallback1({success:true, msg:’User details saved successfully’})”>Sample response 1 – through DWR call</button>

<br/>

<button type=”button” onclick=”dwrCallback2({success:true, msg:’Password has been changed’})”>Sample response 2 – through DWR call</button>

<br/>

<button type=”button” onclick=”dwrCallback3({success:false, msg:’Username must contain only letters!’})”>Sample response 3 – through DWR call </button>

</body>

</html>


In addition to this mechanism, all exceptions can and should be caught using DWREngine.setErrorHandler.




read more ...

NotSerializable exception: PersonManagerImpl

April 20th, 2007 by spostelnicu in Java, General

I recently stumbled across a NotSerializableException in the project I was working, and I decided to share this experience with you because the cause of the problem it’s quite interesting and some of you might come across the same problem.

First of all, the first thing noticed was that the exception was thrown when trying to serialize the http servlet session. By some sort of “accident”, the session contained an object that was not serializable. So far everything seemed normal. The one thing that was wierd about it was that the object in question was an instance of PersonManagerImpl. Let’s say that this is the name of one of the classes in our project. It’s a class that implements some business service interface, named PersonManager.

“Now, wait a minute!”, I said. “How the f*** did that come to be on the session?”

After a closer look, I noticed that the name of the offending class was not actually PersonManagerImpl, but PersonManagerImpl$1.

“A-ha!” That just made it a little easier for me. All I had to look for was to find an anonymous inner class of PersonManagerImpl, and discover how it got to be put on session.

After some digging in the code, I found the following lines (Note: these are not the actual names of classes and methods, but you get the point):


// Get a set of persons by some criteria
Set<Person> persons = personDao.findSomePersons(someCriteria);
// Sort the set of persons by some criteria (because the DAO method returned an unsorted Set)
TreeSet sortedSet = new TreeSet(new Comparator<Person>() {
public int compare(Person p1, Person o2) {
return p1.getPosition().compareTo(p2.getPosition());
}
});
sortedSet.addAll(persons);
session.setAttribute(SOME_PERSONS, sortedSet);

So, to make it all clear: what happened here was that the sorted set was saved as a session attribute, but along with it was also saved the Comparator, which was declared as an anonymous inner class of PersonManagerImpl.

To fix this annoying bug, the easy solution was to make the Person class implement Comparable:

public class Person implements Serializable, Comparable {
…….

public int compareTo(Object o) {
Person that = (Person) o;
return this.position.compareTo(that.position);
}
}

and change the sorting code to:


Set sortedSet = new TreeSet();
sortedSet.addAll(persons);

read more ...

Avoid Spring circular references and over eager type matching using lazy initialization

April 5th, 2007 by Marius Hanganu in Java, General, Spring

Circular dependencies between beans managed by Spring is usually caused by a logic error, but it may be sometimes exactly what developers intend to obtain.



We recently ran into this problem: Spring seems to “over-eagerly” initialize the beans, resulting in an circular dependency error.



2007-04-05 13:24:41,310 ERROR [main] context.ContextLoader (ContextLoader.java:205) – Context initialization failed

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name ‘articleManager’: Bean with name ‘*********’ has been injected into other beans [******, **********, **********, **********] in its raw version as part of a circular reference,

but has eventually been wrapped (for example as part of auto-proxy creation). This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching – consider using ‘getBeanNamesOfType’ with the ‘allowEagerInit’ flag turned off, for example.




We managed to overcome the problem by using the “lazy-init” attribute for our Spring beans. Other techniques for avoiding/fixing the problems are described by Costin Leau and Andreas Senft on the spring framework’s forums here and here.




read more ...

Illegal attempt to associate a collection with two open sessions

March 5th, 2007 by Marius Hanganu in Java, General

This is a minor problem, but it may help some of you out there. The error can occur from several reasons, but in this case it was due to bad use of cascade update. The exception I received was:

org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
at org.hibernate.collection.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:410)
at org.hibernate.event.def.OnUpdateVisitor.processCollection(OnUpdateVisitor.java:40)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55)
at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:123)

The problem was due to a misuse of cascade update in one of the mappings. The field was declared as follows:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = “user_id”)
public User getAuthor() {
return author;
}

Removing the cascade = CascadeType.ALL fixed the problem.
Conclusion: carefully use cascade updates as it may get you into trouble. Use it when business logic requires it. In the example below there was no need for it, so removing it was both business and programatically a good decision.

technorati tags:, , , ,

read more ...

Chaining multiple view resolvers in Spring – using two InternalResourceViewResolver

March 1st, 2007 by Marius Hanganu in Java, General, Spring

Spring allows chaining of multiple view resolvers . However, there are some view resolvers like the ones extending UrlBasedViewResolver which must be the last in the chain, hence the limitation of having only one such view resolver in your chain.
Javadoc for UrlBasedViewResolver mentions: “Note: When chaining ViewResolvers, a UrlBasedViewResolver always needs to be last, as it will attempt to resolve any view name, no matter whether the underlying resource actually exists.”

There are however situations in which one needs chaining multiple view resolvers such as InternalResourceViewResolver or UrlBasedViewResolver. For example, you need to support views returned both as JSP pages and Tiles layouts.

Chaining two InternalResourceViewResolver won’t do the job, since the first one will always try to resolve your view, and it will fail either on the JSP page or Tiles layout.

In order to support this feature you have to write your own view resolver extending UrlBasedViewResolver. Here’s an idea on how you can chain these resolvers: your custom view resolver can analyze the view returned by your Spring MVC controller and check its name. If it’s name contains the suffix “.layout”, your ViewResolver will pass control to the other view resolvers in the chain. Here’s a sample code:

/**
* Custom view resolver – checks if view name contains string layout, in which case lets the request
* reach the other view resolvers in the chain
*
* @author Marius Hanganu
*/
public class MyViewResolver extends UrlBasedViewResolver implements Ordered {
    /**
    * Overrides loadView in UrlBasedViewResolver to be able to make a     difference when letting the other views
    * in the chaing take control of the request
    *
    * @see org.springframework.web.servlet.view.UrlBasedViewResolver#loadView(String,java.util.Locale)
    */
    protected View loadView(String viewName, Locale locale) throws Exception {
    AbstractUrlBasedView view = buildView(viewName);
    View viewObj = (View)     getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName);
        if (viewObj instanceof JstlView) {
            JstlView jv = (JstlView) viewObj;
            if (jv.getBeanName().indexOf(“layout”) != -1) {
                return null;
            }
        }

        return viewObj;
    }
}

The only other thing one needs to do is to declare the view resolvers.

<bean id=”viewResolver” class=”ro.tremend.bigg.web.spring.BiggViewResolver”>
    <property name=”order” value=”1″/>
    <property name=”viewClass” value=”org.springframework.web.servlet.view.JstlView”/>
    <property name=”prefix” value=”/WEB-INF/jsp/”/>
    <property name=”suffix” value=”.jsp”/>
</bean>

<bean id=”tilesViewResolver” class=”org.springframework.web.servlet.view.InternalResourceViewResolver”>
    <property name=”order” value=”2″/>
    <property name=”requestContextAttribute” value=”requestContext”/>
    <property name=”viewClass” value=”org.springframework.web.servlet.view.tiles.TilesJstlView”/>
</bean>

read more ...

AJAX file upload monitoring – monitor your file upload with DWR and commons-fileupload

March 1st, 2007 by Marius Hanganu in HTML, Javascript, Java, General

Monitoring your file upload using ajax is a must have for any web 2.0 application. There are already some good examples developed by prosson and carsonm.

The first one looks great, but it is VERY slow. Takes several minutes to upload a file of 40M on localhost on my Core Duo which is Unnaceptable.

Fortunately, the second has the right speed. Actually it has it all, being written with prototype. The version I’m posting on this entry is just a variation to the version posted on mission data blog, using DWR. You can download all sources and dependencies along with Intellij IDEA project here.

The mechanism is simple and works like this:

  1. upload request is made with a dummy target (an embedded invisible iframe)
  2. on the server side, the upload servlet starts monitoring the upload and sets some objects on the session
  3. on the client side, a request for checking progress is made shortly after the upload has been triggered
  4. using DWR this request goes to a DWR proxy on the server side which returns some statistics
  5. when the upload servlet finished the upload, it will signal this to the DWR proxy, so that the next request for progress will be the last one

To integrate this in your own application you must do the following:

1. In web.xml declare the upload servlet and the dwr servlet (if it’s not there already):

    <servlet>

        <servlet-name>UploadServlet</servlet-name>

        <servlet-class>ro.tremend.upload.UploadServlet</servlet-class>

    </servlet>



    <servlet>

        <servlet-name>dwr-invoker</servlet-name>

        <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>

        <init-param>

            <param-name>debug</param-name>

            <param-value>true</param-value>

        </init-param>

        <init-param>

            <param-name>scriptCompressed</param-name>

            <param-value>true</param-value>

        </init-param>

        <load-on-startup>2</load-on-startup>

    </servlet>



    <servlet-mapping>

        <servlet-name>UploadServlet</servlet-name>

        <url-pattern>/Upload</url-pattern>

    </servlet-mapping>



    <servlet-mapping>

        <servlet-name>dwr-invoker</servlet-name>

        <url-pattern>/dwr/*</url-pattern>

    </servlet-mapping>



2. In dwr.xml declare your proxy and a converter for the status object returned to UI:

    <create creator=”new” javascript=”uploadProxy”>

        <param name=”class” value=”ro.tremend.upload.UploadProxy”/>

    </create>



    <convert converter=”bean” match=”ro.tremend.upload.UploadStatus”/>



3. In your jsp or html page add the following:

    <iframe id=’target_upload’ name=’target_upload’ src=” style=’display: none’></iframe>



    <form enctype=”multipart/form-data” name=”form” method=”post” action=”Upload” onsubmit=”return startUploadMonitoring();” target=”target_upload”>

        File to upload: <input id=”importFile” name=”importFile” type=”file”> <br/>

        <input id=”submitButton” type=”submit” value=”Upload”/>

    </form>



    <div id=”uploadStatus”>

        <!– specify width on this uploadProgressBar, otherwise the progress indicator won’t move –>

        <div id=”uploadProgressBar” style=”width:200px;”>

            <div id=”uploadIndicator”></div>

        </div>

        <div id=”uploadPercentage”></div>

    </div>



The iframe is used to swallow the response to the upload request. The form contains the upload fields and the button. The uploadStatus div will hold the progress monitor.



4. In the head section of your jsp or html you will have to add the following:



    <style type=”text/css”>

        #uploadStatus {

            width: 230px;

        }



        #uploadProgressBar {

            height: 14px;

            border: 1px solid #BBB;

            text-align: center;

            display: inline;

            float: left;

        }



        #uploadIndicator {

            height: 10px;

            position: relative;

            margin: 1px;

            padding: 1px;

            background: #9DC0F4;

            width: 0;

            float: left;

        }



        #uploadPercentage {

            width: 20px;

            display: inline;

            float: right;

        }

    </style>



    <script type=’text/javascript’ src=”dwr/util.js”></script>

    <script type=’text/javascript’ src=”dwr/engine.js”></script>

    <script type=”text/javascript” src=”dwr/interface/uploadProxy.js”></script>



    <script type=”text/javascript” language=”JavaScript”>

        var updater = null;



        function checkStatus() {

            uploadProxy.getStatus(function(stat) {

                if (stat.status == 2) {

                    updateProgressBar(100);

                    return;

                }



                if (stat.status == 3) {

                    alert(“An error has occured! ” + stat.message);

                    return;

                }



                if (stat.status == 4) {

                    alert(“An error has occured! ” + stat.message);

                    return;

                }



                // do something with the percentage (nice loading bar, simply show the percentage, etc)

                updateProgressBar(stat.percentComplete);

                window.setTimeout(“checkStatus()”, 500);

            });

        }



        function updateProgressBar(percentage) {

            // make sure you set the width style property for uploadProgressBar, otherwise progress.style.width won’t work

            var progress = document.getElementById(“uploadProgressBar”);

            var indicator = document.getElementById(“uploadIndicator”);

            var maxWidth = parseIntWithPx(progress.style.width) – 4;

            var width = percentage * maxWidth / 100;

            indicator.style.width = width + “px”;

            var perc = document.getElementById(“uploadPercentage”);

            perc.innerHTML = percentage + “%”;

        }



        function parseIntWithPx(str) {

            var strArray = str.split(“p”);

            return parseInt(strArray[0]);

        }



        function startUploadMonitoring() {

            window.setTimeout(“checkStatus()”, 500);

            return true;

        }

</script>



5. You can assign unique identifiers to the set of files you’re uploading. The UploadServlet will make sure when upload finished to make

all files available on the HttpSession object under the key you’ve specified. To do that you’ll have to:

    a) add a new field inside the form:

        <input type=”hidden” name=”uniqueFileIdentifier” value=”1234″/>

    b) in your java code, you can retrieve the files uploaded like this:

        List filesUploaded = (List) session.getAttribute(UploadServlet.FILES_UPLOADED);



   
This will return a list of FileItem objects (for more information check the commons file upload documentation).


technorati tags:, , , , ,

read more ...

Hibernate Annotations 3.2.1 – Lucene sort

February 28th, 2007 by Ioan Cocan in Java, General

Keeping database and Lucene index in sync is easily done using the new Lucene-Hibernate integration.

Just place the default org.hibernate.search.event.FullTextIndexEventListener on Hibernate’s lifecycle methods, configure the Lucene annotations in classes you want to search and you’re ready to go. For custom operations such as persisting custom classes you can write bridges where you can create custom fields in index.

Save/update/deletes of your hibernate objects will propagate in Lucene index. A full reindex can be implemented as well using a custom the new FullTextSession class.

Everything is great on the keeping in sync part, but how about doing actual searches?

The intent was to wrap actual Lucene queries and have them transformed into Hibernate queries, empowering the API user with all the API Hibernate provides for query manipulation (eg. pagination). Problem is getting a hold of the actual Lucene index is no longer possible. All that nicely created and maintained in sync index cannot be used with real Lucene queries, using Lucene API to extract the information.

A simple problem was using Lucene to do a Sort for me, turns out that current API does not provide that. As I understand, 3.3.0 will allow direct access to Lucene Directory (see here). To get around that you can use something similar to SearchDAO.java using the same index access as Lucene-Hibernate integration is using.

read more ...

Serializable java objects in MySQL

February 15th, 2007 by Sebastian Mitroi in Java, General

How to save a complex java object in a MySQL table

If you want to save complex java objects to MySQL you can serialize and save them as BLOB in a MySQL table.

For example you have an object “complexObject” from class “ComplexObject” and you want to save it in database.

The ComplexObject class must implements Serializable interface and you can serialize the objects like this:

ByteArrayOutputStream baos;

ObjectOutputStream out;

baos = new ByteArrayOutputStream();

try {

out = new ObjectOutputStream(baos);

out.writeObject(complexObject);

out.close();

} catch (IOException e) {

e.printStackTrace();

}

byte[] byteObject = baos.toByteArray();

to deserialize the object :

ByteArrayInputStream bais;

ObjectInputStream in;

try {

bais = new ByteArrayInputStream(byteObject);

in = new ObjectInputStream(bais);

complexObject = (ComplexObject) in.readObject();

in.close();

} catch (IOException ex) {

ex.printStackTrace();

} catch (ClassNotFoundException ex) {

ex.printStackTrace();

}

The MySQL table looks like this:

CREATE TABLE myTable(



complexObject BLOB,…

);

If you use Hibernate and Annotation you declare the complexObject transient, and a byte[] byteObject that will be persisted:

@Entity

@Table(name = “myTable”)

SomeClass{

private byte[] byteObject;

private ComplexObject complexObject;



@Transient

public ComplexObject getComplexObject() {

return complexObject;

}

public void setComplexObject(ComplexObject complexObject) {

this.complexObject = complexObject;

ByteArrayOutputStream baos;

ObjectOutputStream out;

baos = new ByteArrayOutputStream();

try {

out = new ObjectOutputStream(baos);

out.writeObject(complexObject);

out.close();

} catch (IOException e) {

e.printStackTrace();

}

this.byteObject = baos.toByteArray();

}

@Column(columnDefinition = “blob”)

public byte[] getByteObject() {

return byteObject;

}

public void setByteObject(byte[] byteObject) {

ByteArrayInputStream bais;

ObjectInputStream in;

try {

bais = new ByteArrayInputStream(byteObject);

in = new ObjectInputStream(bais);

complexObject = (ComplexObject) in.readObject();

in.close();

} catch (IOException ex) {

ex.printStackTrace();

} catch (ClassNotFoundException ex) {

ex.printStackTrace();

}

this.byteObject= byteObject;

}

}

Attention the table column must be BLOB, not varchar.

Because the ComplexObject is transient it will not be save in database, but the byteObject will be save.


read more ...

Create and populate your database independent of the db server using ant, dbunit and hibernate

January 31st, 2007 by Martin Paraschiv in Java, General

    Database creation is such a common task that you must have some scripts and tips and tricks at hand, in order to have it done as quickly as possible. What about when there’s more than one type of RDBMS in your project that you need to handle. Things get a little messy.
     How about using just one XML file and two or three libraries, regardless of the RDBMS type. Wouldn’t that be cool?
     I’m saying, all you need is ant, dbunit and Hibernate as libraries and a couple of files for data and database connection configuration. With this you’ll be able to populate with only one file init-dataset.xml different rdbms like Oracle, MySql, MsSql, Postgres. For a complete list of supported rdbms have a look at dbunit SupportedRDBMS
Database creation and population process is in four steps:
    1.Create an ant build.xml file and setup a project with path for used libraries
    2.Generate DDL from Hibernate mapping
    3.Create database schema running generated DDL
    4.With DBUnit populate database created above, providing as input a seed XML file with data you’re database must be populated with.

    1.
     <project name=”OMS” basedir=”.” default=”deploy-reload-classes”>
         <property file=”web/WEB-INF/classes/db.properties“/>
         <property name=”ddl.file” value=”ddl.sql”/>
         <property name=”lib.dir” value=”lib”/>

         …

         <path id=”project.classpath”>
         <fileset dir=”${lib.dir}”>
         <include name=”**/*.jar”/>
         </fileset>
         </path>

         <!– dbnunit task definition –>
         <taskdef name=”dbunit”
         classname=”org.dbunit.ant.DbUnitTask”
         classpathref=”project.classpath”/>

         </project>

Typical ant project setup. In order to use dbunit task we need to define it.

     2.
     <target name=”hbm2ddl-schema” description=”Generate DDL from Hibernate mapping”     depends=”build”>
         <java classname=”net.sf.hibernate.tool.hbm2ddl.SchemaExport” fork=”true”>

         <!– Hibernate Properties –>
         <jvmarg value=”-Dhibernate.dialect=${databaseDialect}”/>

         <!– Mapping Files –>
         <arg value=”ObjectModel.hbm.xml”/>

         …

         <classpath refid=”project.classpath”/>

         </java>
     </target>

These lines should be familiar to an hibernate user.

     3.
     <target name=”sql-run-ddl” description=”Run DDL script” depends=”hbm2ddl- schema”>
         <sql url=”${databaseURL}” driver=”${databaseDriver}”
         userid=”${databaseUser}” password=”${databasePassword}”
         onerror=”continue” autocommit=”true” print=”yes”>
         <classpath refid=”project.classpath”/>
         <transaction src=”${ddl.file}”/>
         </sql>
     </target>

all database related variables should be defined into a properties file, I called it db.properties, see step 1.

     4.
     <target name=”dbunit-init-db” description=”using dbunit for testing” depends=”sql-run-ddl”>
         <dbunit driver=”${databaseDriver}”
         url=”${databaseURL}”
         userid=”${databaseUser}”
         password=”${databasePassword}”>
         <operation type=”DELETE”
         src=”db/defaults/init-dataset.xml”/>
         <operation type=”INSERT” format=”flat”
         src=”db/defaults/init-dataset.xml”/>
         </dbunit>
     </target>

after initializing database we can populate it.

     For a simple database setup the script above should do it.
     But sometimes we need to initialize more complex databases, where we have some foreign key circular dependency.

Some Tips & Tricks

     Unfortunately dbunit is not perfect, meaning it has some bugs. One is that it doesn’t handle too well circular reference between tables, and second is when a db is initialized. At initialization operation, in the seed dataset file each new row for each new table must have all fields populated, otherwise unpopulated fields (from first row, but populated in subsequent rows) will be set to null;
     Here are some workarounds.
    1.instead of using a row with missing column, use one with complete columns.
    For example:
     using

         <dataset>
             <user ID=’1′ />
             <user ID=’2′ NAME=’user name’/>
         </dataset>

     will insert null in all NAME columns of user table. The solution is to use

     <dataset>
         <user ID=’2′ NAME=’user name’ />
         <user ID=’1′ />
     </dataset>

    1.instead of using INSERT operation, use REFRESH operation.At REFRESH operation, data of existing rows are updated and non-existing rows get inserted. For clean initalization, perform CLEAN before.

     <dataset>
         <user ID=’1′ col2=’val1′/>
         <user ID=’2′ NAME=’user name’ col2=’val2′/>
         <!– if met twice id=2, than the second time it means there’s an update –>
         <user ID=’2′ NAME=’user name’ />
     </dataset>

    In the update part you must update only fields that you know they were setup to null.
    The second method is also useful when you need to populate a db with data that contains circular reference. Let’s suppose we have users and portfolios. And for some reason we would like to have a reference of an portfolio into user’s table, and a reference of user into portfolio table. The data will look something like this:

     <dataset>
         <user ID=’1′ name=’default user’ portfolio_id=’1′ />
         <portfolio ID=’1′ user_id=’1′ name=”default portfolio”/>
</dataset>

     If we’ll use the dataset above with INSERT operation, dbunit will report an error, that portfolio with id=1 doesn’t exists.

    Using REFRESH operation, with an appropriate dataset the problems will disappear.

     <dataset>
         <user ID=’1′ name=’default user’ />
         <portfolio ID=’1′ user_id=’1′ name=”default portfolio”/>
         <!– if met twice id=2, than the second time it means there’s an update –>
         <user ID=’2′ NAME=’user name’ portfolio_id=’1′/>
     </dataset>

     As you can see portfolio_id is missing from the first row. So dbunit gets fooled. Next record will be inserted with reference to user table. And the last record will update reference of user record to portfolio record.

    The bottom line: in spite of it’s imperfections, dbunit has reached 2.2 version after more than one year breakend, it can be used very efficiently for other purposes than database testing. A database setup operation independent of RDBMS type can be done easily enough with DBUnit. I hope you find this interpretation useful.

Good luck!

Read the rest of this entry »

read more ...

My experience with web services with Spring, Axis, XFire

January 22nd, 2007 by spostelnicu in Java, General, Spring

First thing to note is that, this being my first contact with web services (SOAP and WSDL), it took me quite a lot of time (almost five working days) to learn about the technologies involved and try to implement and publish a web service in my application.

Of these four and a half working days (36 hours), about 14 cumulated hours were spent stepping through the library code, trying to determine the causes for various errors (especially for XFire, which returned all sorts of cryptic and unhelping error messages).

1) First try: Apache Axis

The first day was dedicated to learning about Axis and trying what it can do.

The second day was dedicated to writing and testing the necessary configurations to publish my specific service, which contained many service methods and serializable classes.

My opinion after this short experience is this: the setting up of the service with Axis seems to be too complicated for my simple needs.

After writing the service interface, you have to run two tools: Java2WSDL and WSDL2Java. The first one will generate the WSDL for the web service. The second one will generate auxilliary classes: remote interface, client stub, service locator helper – all of them hard-coded for my service.

Of course, to integrate them into a build process you have to learn to use the ant tasks for Java2WSDL and WSDL2Java, and after the code generation, compile the generated files.

And then you have to take care of the deployment of the service by using the generated deployment.xml, and I didn’t quite understand how to automate the deployment (the documentation was not very clear about this).

All I needed was some kind of generic Java class to expose web services by proxying SOAP calls to a Spring managed bean that implemented my interface. Something like: WebServiceFactory.create(MyServiceInterface.class).

I didn’t want no WSDL or XMLSchema or namespaces or some other messy XML stuff.

And for the client part, something like this was desirable: WebServiceProxyFactory.create(MyServiceInterface.class)

Which, fortunately, I actually found the next day in the form of XFire.

2) Second try: XFire

The third day I decided to switch to XFire, because of its simpler usage (no more WSDL, no more deployment.xml, no more two-steps build with Java2WSDL and WSDL2Java…)

So I tried to learn about services.xml and xfire-servlet.xml and stuff.

The first thing that sticks out is the “not-so-complete” documentation and with the way that XFire just doesn’t like to show useful error messages. Most of the errors are either silently ignored, or replaced by some generic message like “Invalid SOAP request”.

One big problem that I had was that at first I tried to access the XFire service with the Axis client that I already have. Big mistake! After half a day of stepping through the XFire code, I discovered that the problem was that my client was sending a request as RPC/encoded, which XFire does not support. And instead of telling me that, XFire was simply returning a fault with the internal exception message, which was: “ Index: 1, Size: 1 “.

Imagine my frustration! I didn’t have any clue as to what this can mean. Could it have something to do with the SOAP elements? Could it be some internal tables used? Could it mean the index of the method parameters? And, most annoying: is this an ERROR MESSAGE? What is the error? “Index: 1, Size: 1″ – I don’t see any error in here!

Of course searching the web didn’t help me in this case, so I started debugging the XFire service handlers, and learning the XFire insides along the way.

After about an hour I discovered that this was no more than an IndexArrayOutOfBoundsException! It seems I haven’t met one very often in my days, otherwise I could have been able to recognise the error message. But XFire didn’t return in the fault message the name of the exception, it returned just the error message. And no error logging. And of course, do not even dare to ask a stacktrace.

Anyway, eventually I discovered that the exception was caused because the handler wasn’t able to recognise the format of the SOAP request, which contained multiref elements. After googling some more and not finding any reference to multiref and XFire, I eventually found that the multirefs were there because of the RPC/encoded format – which, no need to mention, I had very little knowledge about. Remember, this was my first contact with SOAP, and I wasn’t in the mood to learn all the “subtleties” of the protocol. I just wanted to expose my service with the least effort.

The fourth day I learned how to expose services with XFire by using JSR 181 Annotations. Because of the incomplete documentation and examples, this caused a problem that took me 3 hours to debug and still couldn’t solve until next day: the service class wasn’t accesible through XFire, which just kept returning empty pages (another annoying behaviour: no error message, no 404, no service fault, no “Invalid SOAP request”, no nothing. Just a blank page with the footer “Generated by XFire”)

I couldn’t tell if it was a problem with SimpleUrlMapper, or with Jsr181HandlerMapping, or if I should use DispatcherServlet instead of XFireSpringServlet…

The documentation contained very confusing examples, in which a SimpleUrlMapper had a mapping from “/” to handlerMapping, and handlerMapping was a Jsr181HandlerMapping. My confusion was: what does Jsr181HandlerMapping do? It’s another URL mapper? And if it is, when are the Spring beans initialized?

The next morning I finally discovered the cause for the last problem encountered.

After yet another session of analysing the XFire source code, it was clear for me that Jsr181HandlerMapping was not an URL mapper. Actually, all it did was to call XFire to register my classes that had @WebService annotations. But then again, why didn’t it work?

To configure this part, I followed an example that I found on some blog, because the XFire documentation lacked this part. I actually followed exact steps showed in the example, along with the example classes and settings. And what frustrated me more was that his conclusion was “So we see that setting up web services by using XFire and JSR 181 annotations is a no brainer.” If it is a no brainer, why it doesn’t work ?! :p

But apparently the author of the example forgot to mention that in order for this to work, you have one more thing to configure: to add your bean in applicationContext.xml

In his example this step was missing, so of course the service was not registered, because (as I found out after analysing the XFire source code) Jsr181HandlerMapping checked all the already configured beans to see if they had @WebService annotation.

So in conclusion:

  • XFire is indeed very easy to configure (if you follow a complete example, like this one that I found later), but lacks many “advanced” SOAP features.
  • Axis is more advanced, more configurable and with more advanced SOAP and WSDL features, but a “little” bit more difficult to configure.

technorati tags:, , , , ,

read more ...

Cryptic fault when trying to call an XFire SOAP service using a SOAP client generated with Axis

January 22nd, 2007 by spostelnicu in Java, General

I encountered a problem when trying to call an XFire SOAP service using a SOAP client generated with Axis, and after finding the “solution” I decided to share it with you so you won’t have to repeat my steps.

I’ll be short:

When trying to call an XFire SOAP service using a SOAP client generated with Axis, I get the following (very cryptic) fault:

Index: 1, Size: 1
AxisFault
faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server
faultSubcode:
faultString: Index: 1, Size: 1
faultActor:
faultNode:
faultDetail:
{http://xml.apache.org/axis/}stackTrace:Index: 1, Size: 1

This is generated by an internal IndexArrayOutOfBoundsException (which I couldn’t determine only after step-by-step debugging through the XFire sources), at line 191 in org.codehaus.xfire.service.binding.AbstractBinding (xfire-distribution-1.2.4-sources.jar):

p = (MessagePartInfo) opInfo.getInputMessage().getMessageParts().get(param);

Basically, the parser is trying to get the next xml element in the request, which doesn’t exist.

When examining the SOAP message, I found this:

<soapenv:Body>
<ns1:myMethod soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns1="urn:MyNamespace">
<in0 href="#id0" />
</ns1:myMethod>
<multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
........

So it seems that the request is using RPC encoding, which unfortunately XFire doesn't support.

In conclusion: do not access a service published with XFire with a client generated by Axis, unless you change the default request encoding style from RPC/Encoded to WRAPPED/Literal.

technorati tags:, , , ,


Spring and Tiles – presentation tier in http://www.123urban.ro

November 1st, 2006 by Marius Hanganu in Java, General, Spring

Presentation tier in 123urban – Spring comes to the rescue as usual with its embedded support for Tiles. Basically, the only setting is to change your viewResolver in your -servlet.xml from JstlView to TilesView.

   <bean id=”viewResolver” class=”org.springframework.web.servlet.view.InternalResourceViewResolver”>        

<property name=”requestContextAttribute” value=”requestContext”/>

<property name=”viewClass” value=”org.springframework.web.servlet.view.tiles.TilesJstlView”/>

</bean>


Notice the use of TilesJstlView a specialization of TilesView which offers support for JSTL pages.

From here on is just as easy as a walk in the park – classic Tiles -> tiles.xml stays in WEB-INF and works like a charm. You should be aware that from now on all your responses will go through Tiles which means all your Spring MVC controllers will have to define their views as being Tiles layouts.


« Previous Entries Next Entries »