<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CUMBQns5fyp7ImA9WhRVGUw.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109</id><updated>2012-01-18T20:04:13.527+01:00</updated><category term="ruby" /><category term="conf" /><category term="connector" /><category term="mobile" /><category term="yui" /><category term="xml" /><category term="hibernate" /><category term="wurfl-browser" /><category term="javascript" /><category term="java" /><category term="mysql" /><category term="vacation" /><category term="REST" /><category term="jaxb" /><category term="php" /><category term="ajax" /><category term="jersey" /><category term="tomcat" /><category term="collection" /><category term="validator" /><category term="flex" /><category term="vhost" /><category term="dwr" /><category term="blogger" /><category term="paris" /><category term="struts" /><category term="framework" /><category term="jms" /><category term="mod_jk" /><category term="database" /><category term="enums" /><title>julius dev</title><subtitle type="html">A french dev2dev blog.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://juliusdev.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/JuliusDev" /><feedburner:info uri="juliusdev" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;D0YAQXYzeCp7ImA9WxNXFEo.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-4879326777997736276</id><published>2009-10-02T10:39:00.007+02:00</published><updated>2009-10-02T11:19:00.880+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-02T11:19:00.880+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="jms" /><title>My download queue hangs !</title><content type="html">&lt;p&gt;
I developed a simple download queue with Spring jms and Activemq. The client send message which contains a list of file's urls, the message is put in the the jms queue and it's dispatched to consumers (listeners). Each consumer tries to download files and save them on the disk. Pretty simple isn't it ? 
&lt;/p&gt;
&lt;p&gt;
Problem After few days or messages my consumer stop and the number of concurrent consumer reach the max limit.  Each consumer thread status was RUNNABLE on my server. 
&lt;/p&gt;
I analyzed the thread and found that :
&lt;pre&gt;
java.net.SocketInputStream.socketRead0 ( native code )
java.net.SocketInputStream.read ( SocketInputStream.java:129 )
java.io.BufferedInputStream.fill ( BufferedInputStream.java:218 )
java.io.BufferedInputStream.read1 ( BufferedInputStream.java:258 )
java.io.BufferedInputStream.read ( BufferedInputStream.java:317 )
sun.net.www.MeteredStream.read ( MeteredStream.java:116 )
java.io.FilterInputStream.read ( FilterInputStream.java:116 )
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read ( HttpURLConnection.java:2446 )
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read ( HttpURLConnection.java:2441 )
org.apache.commons.io.IOUtils.copy ( IOUtils.java:920 )
org.apache.commons.io.FileUtils.copyURLToFile ( FileUtils.java:659 )
com.cellfish.mediadb.ws.encoder.MediaDBFeeds.downloadFile ( MediaDBFeeds.java:468 )
com.cellfish.jms.MsgFromEncoderListener.onMessage ( MsgFromEncoderListener.java:59 ) 
&lt;/pre&gt;

I used the method FileUtils.copyURLToFile(URL url, File destFile) from the common io library to download and write files. This method have no connection and no read timeout :
&lt;pre name="code" class="java"&gt;
    //-----------------------------------------------------------------------
    /**
     * Copies bytes from the URL &lt;code&gt;source&lt;/code&gt; to a file
     * &lt;code&gt;destination&lt;/code&gt;. The directories up to &lt;code&gt;destination&lt;/code&gt;
     * will be created if they don't already exist. &lt;code&gt;destination&lt;/code&gt;
     * will be overwritten if it already exists.
     *
     * @param source A &lt;code&gt;URL&lt;/code&gt; to copy bytes from.
     * @param destination A non-directory &lt;code&gt;File&lt;/code&gt; to write bytes to
     * (possibly overwriting).
     *
     * @throws IOException if
     * &lt;ul&gt;
     *  &lt;li&gt;&lt;code&gt;source&lt;/code&gt; URL cannot be opened&lt;/li&gt;
     *  &lt;li&gt;&lt;code&gt;destination&lt;/code&gt; cannot be written to&lt;/li&gt;
     *  &lt;li&gt;an IO error occurs during copying&lt;/li&gt;
     * &lt;/ul&gt;
     */
    public static void copyURLToFile(URL source, File destination)
                throws IOException {
        //does destination directory exist ?
        if (destination.getParentFile() != null
            &amp;&amp; !destination.getParentFile().exists()) {
            destination.getParentFile().mkdirs();
        }

        //make sure we can write to destination
        if (destination.exists() &amp;&amp; !destination.canWrite()) {
            String message =
                "Unable to open file " + destination + " for writing.";
            throw new IOException(message);
        }

        InputStream input = source.openStream();
        try {
            FileOutputStream output = new FileOutputStream(destination);
            try {
                IOUtils.copy(input, output);
            } finally {
                IOUtils.closeQuietly(output);
            }
        } finally {
            IOUtils.closeQuietly(input);
        }
    }
&lt;/pre&gt;

Sometimes the http connection hangs and the consumer is never released.

I propose the following patch for the copyURLToFile method :

&lt;pre name="code" class="java"&gt;
public static void copyURLToFile(URL source, File destination, int connectTimeOut, int readTimeOut )
                throws IOException {
        //does destination directory exist ?
        if (destination.getParentFile() != null
            &amp;&amp; !destination.getParentFile().exists()) {
            destination.getParentFile().mkdirs();
        }

        //make sure we can write to destination
        if (destination.exists() &amp;&amp; !destination.canWrite()) {
            String message =
                "Unable to open file " + destination + " for writing.";
            throw new IOException(message);
        }
        
        URLConnection cnx = source.openConnection();
        cnx.setReadTimeout(readTimeOut);
        cnx.setConnectTimeout(connectTimeOut);
        
        InputStream input = cnx.getInputStream();
        try {
            FileOutputStream output = new FileOutputStream(destination);
            try {
                IOUtils.copy(input, output);
            } finally {
                IOUtils.closeQuietly(output);
            }
        } finally {
            IOUtils.closeQuietly(input);
        }
    }
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-4879326777997736276?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/4879326777997736276/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=4879326777997736276" title="37 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/4879326777997736276?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/4879326777997736276?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/TSBCPJd-PZk/my-download-queue-hangs.html" title="My download queue hangs !" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>37</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2009/10/my-download-queue-hangs.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D04FR3w4fyp7ImA9WxdUFE8.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-8918960928343848310</id><published>2008-07-30T15:49:00.002+02:00</published><updated>2008-07-30T15:51:56.237+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-30T15:51:56.237+02:00</app:edited><title>Oil Addiction</title><content type="html">Le prix du pétrole ne cesse de monter sur fond de crise financière. Pour ceux qui n'ont pas bien saisie la situation je vous recommande cette excellente vidéo :

&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/EOm18c5Btiw&amp;hl=en&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/EOm18c5Btiw&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-8918960928343848310?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/8918960928343848310/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=8918960928343848310" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/8918960928343848310?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/8918960928343848310?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/J6Y77UxjNjM/oil-addiction.html" title="Oil Addiction" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/07/oil-addiction.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkUGQH0_eip7ImA9WxdVFkk.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-8912014506349368472</id><published>2008-07-21T15:25:00.005+02:00</published><updated>2008-07-21T15:50:21.342+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-21T15:50:21.342+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="REST" /><category scheme="http://www.blogger.com/atom/ns#" term="jersey" /><title>Jersey REST (JSR-311) and JSON part II</title><content type="html">In a previous post we have seen how to create a REST resource which produces a JSON or XML output with jaxb and jettison.  In this post i'll use &lt;a href="http://flexjson.sourceforge.net/" &gt;flexjson&lt;/a&gt; to produce a JSON output from my objects which can be customized.
&lt;br/&gt;
I have the following classes in my domain model :
&lt;pre&gt;
Product &amp;lt;-_has_many_-&amp;gt; Categorie
&lt;/pre&gt;

If you want to serialize the a product object with their categories. Just add the flexjson.jar to your webapp add this lines : &lt;br/&gt;
&lt;pre name="code" class="java"&gt;
    @GET
    @Path("{id}")
    @ProduceMime("application/json")
    public String getJSONProduct(@PathParam("id") Integer id){
       return new JSONSerializer().exclude("*.class") // Exclude the property class from the json
                                  .include("categories")
                                  .serialize(product);
    }
&lt;/pre&gt;

See the output :
&lt;pre&gt;
curl -v -H "Accept: application/json" http://localhost:8080/rest-json/resource/product/1
&gt; Host: localhost:8080
&gt; Accept: application/json
&gt; 
&lt; HTTP/1.1 200 OK
&lt; Server: Apache-Coyote/1.1
&lt; Content-Type: application/json
&lt; Transfer-Encoding: chunked
&lt; Date: Mon, 21 Jul 2008 13:25:11 GMT
&lt; 
* Connection #0 to host localhost left intact
* Closing connection #0
{"categories":[{"id":1,"name":"mobile"}],
"description":"A great mobile device !",
"id":1,"name":"iphone"}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-8912014506349368472?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/8912014506349368472/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=8912014506349368472" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/8912014506349368472?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/8912014506349368472?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/G0CpXgijXDE/jersey-rest-jsr-311-and-json-part-ii.html" title="Jersey REST (JSR-311) and JSON part II" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/07/jersey-rest-jsr-311-and-json-part-ii.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkUNQHoyeCp7ImA9WxdVGUU.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-8930183534527973910</id><published>2008-07-07T23:19:00.013+02:00</published><updated>2008-07-25T12:04:51.490+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-25T12:04:51.490+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="REST" /><category scheme="http://www.blogger.com/atom/ns#" term="jersey" /><title>Jersey REST (JSR-311) and JSON</title><content type="html">With Jersey it's very easy to create a RESTfull resource which returns an XML version of your objects:
&lt;pre name="code" class="java"&gt;
    @GET
    @Path("{id}")
    @ProduceMime("application/xml")
    public Product getProduct(@PathParam("id") Integer id) {
        //...
        return product;
    }
&lt;/pre&gt;

Jersey uses JAXB to marshall the product object to XML. You can also customize the XML output with jaxb annotations.  
&lt;pre name="code" class="java"&gt;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Product implements Serializable {
    
    @XmlAttribute
    private Integer Id;
    
    //...
}
&lt;/pre&gt;
This customization will produce an XML output that contains a Product element with an id attribute. Ok now,  let's try the service :
&lt;pre&gt;
curl -v -H "Accept: application/xml" http://localhost:8080/rest-json/resources/product/1
&gt; GET /rest-json/resources/product HTTP/1.1
&gt; User-Agent: curl/7.16.3 (powerpc-apple-darwin8.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
&gt; Host: localhost:8080
&gt; Accept: application/xml
&gt; 
&lt; HTTP/1.1 200 OK
&lt; Server: Apache-Coyote/1.1
&lt; Content-Type: application/xml
&lt; Content-Length: 200
&lt; Date: Wed, 09 Jul 2008 20:32:10 GMT
&lt; 
* Connection #0 to host localhost left intact
* Closing connection #0
&amp;lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&amp;gt;
&amp;lt;product id="1"&amp;gt;
 &amp;lt;name&amp;gt;myphone&amp;lt;/name&amp;gt;
 &amp;lt;description&amp;gt;A great mobile device !&amp;lt;/description&amp;gt;
 &amp;lt;category&amp;gt;
  &amp;lt;id&amp;gt;1&amp;lt;/id&amp;gt;
  &amp;lt;name&amp;gt;mobile&amp;lt;/name&amp;gt;
 &amp;lt;/category&amp;gt;
&amp;lt;/product&amp;gt;
&lt;/pre&gt;


To produce a JSON output just add the jettison-1.0-RC1.jar file from the jersey distribution to your webapp and change the mime type parameter of the @ProduceMime annotation like this :
&lt;pre name="code" class="java"&gt;
    @GET
    @Path("{id}")
    @ProduceMime({"application/json","application/xml"})
    public Product getProduct(@PathParam("id") Integer id) {
        //...
        return product;
    }
&lt;/pre&gt;

You have now a REST resource which returns XML or JSON, the response format depends of the Accept header of the HTTP request :
&lt;pre&gt;
curl -v -H "Accept: application/json" http://localhost:8080/rest-json/resources/product/1
&gt; GET /rest-json/resources/product/1 HTTP/1.1
&gt; User-Agent: curl/7.16.3 (powerpc-apple-darwin8.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
&gt; Host: localhost:8080
&gt; Accept: application/json
&gt; 
&lt; HTTP/1.1 200 OK
&lt; Server: Apache-Coyote/1.1
&lt; Content-Type: application/json
&lt; Transfer-Encoding: chunked
&lt; Date: Wed, 09 Jul 2008 20:47:26 GMT
&lt; 
* Connection #0 to host localhost left intact
* Closing connection #0
{"product":{"@id":"1","name":"myphone",
"description":"A great mobile device !",
"category":{"id":"1","name":"mobile"}}}
&lt;/pre&gt;

It's very easy and powerful ! But if you look in details the JSON output you'll notice that the Product's property &lt;i&gt;id&lt;/i&gt; is ""@id":"1"" and not ""id":1" ?!
&lt;p&gt;
In this case the Product object is marshalling by JAXB and converted to JSON by  &lt;a href="http://jettison.codehaus.org/"&gt;JETTISON&lt;/a&gt;. The returned JSON is mapped on the XML object representation.
&lt;/p&gt;
&lt;p&gt;
If you want to produce a more simpler JSON like that :
&lt;pre&gt;
{"product":{"id":1,"name":"myphone"}
&lt;/pre&gt; 
You have to remove all JAXB annotations from the Product classe. You'll lose the XML customization and in some cases the XML output could be too verbose or not readable (for human ).&lt;br/&gt;
You can also use a JSON framework to manage the marshalling process ... &lt;a href="http://juliusdev.blogspot.com/2008/07/jersey-rest-jsr-311-and-json-part-ii.html"&gt;see the part II&lt;/a&gt; :-)
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-8930183534527973910?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/8930183534527973910/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=8930183534527973910" title="1 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/8930183534527973910?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/8930183534527973910?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/VNsb0XZDdqQ/jersey-rest-jsr-311-and-json.html" title="Jersey REST (JSR-311) and JSON" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/07/jersey-rest-jsr-311-and-json.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EFQ3Y-eCp7ImA9WxdXFU8.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-2228559460414596379</id><published>2008-06-27T00:25:00.008+02:00</published><updated>2008-06-27T01:06:52.850+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-27T01:06:52.850+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tomcat" /><title>Tomcat : Add an Expires Header</title><content type="html">One of the Yahoo bests practices for Speeding Up Your Web Site is to &lt;a href="http://developer.yahoo.com/performance/rules.html#expires"&gt; add an &lt;b&gt;Expires&lt;/b&gt; or a &lt;b&gt;Cache-Control Header&lt;/b&gt;&lt;/a&gt;. 
&lt;p&gt;
If you use Tomcat as web-server (Tomcat 6 + NIO have good performances), you can use a Servlet filter to set a far future Expires header for static components like images.
&lt;/p&gt;
Here an example of my servlet filter to set the Expires header :
&lt;pre name="code" class="java"&gt;
public class HeaderFilter implements Filter {

    private static final Log log = LogFactory.getLog(HeaderFilter.class);
    
    private FilterConfig filterConfig;
    
    private Map&amp;lt;String, String&amp;gt; headersMap;

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;

        String headerParam = filterConfig.getInitParameter("header");
        if (headerParam == null) {
            log.warn("No headers were found in the web.xml (init-param) for the HeaderFilter !");
            return;
        }

        // Init the header list :
        headersMap = new LinkedHashMap&lt;String, String&gt;();

        if (headerParam.contains("|")) {
            String[] headers = headerParam.split("|");
            for (String header : headers) {
                parseHeader(header);
            }

        } else {
            parseHeader(headerParam);
        }

        // Log configured headers .
        if (log.isInfoEnabled()) {
            log.info("The following headers were registered in the HeaderFilter :");
            Set&amp;lt;Entry&amp;lt;String, String&amp;gt;&amp;gt; headers = headersMap.entrySet();
            for (Entry&amp;lt;String, String&amp;gt; item : headers) {
                log.info(item.getKey() + ':' + item.getValue());
            }
        }
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (headersMap != null) {
            // Add the header to the response
            Set&amp;lt;Entry&amp;lt;String, String&amp;gt;&amp;gt; headers = headersMap.entrySet();
            for (Entry&amp;lt;String, String&amp;gt; header : headers) {
                ((HttpServletResponse) response).setHeader(header.getKey(), header.getValue());
            }
        }
        // Continue
        chain.doFilter(request, response);
    }

    public void destroy() {
        this.filterConfig = null;
        this.headersMap = null;
    }

    private void parseHeader(String header) {
        String headerName = header.substring(0, header.indexOf(":"));
        if (!headersMap.containsKey(headerName)) {
            headersMap.put(headerName, header.substring(header.indexOf(":") + 1));
        }
    }
}
&lt;/pre&gt;

To use this filter in your webapp, just edit your web.xml to add this lines :

&lt;pre name="code" class="xml"&gt;
    &lt;filter&gt;
        &lt;description&gt;Set HTTP headers for a mapping.&lt;/description&gt;
        &lt;filter-name&gt;HeaderFilter&lt;/filter-name&gt;
        &lt;filter-class&gt;juliusdev.filter.HeaderFilter&lt;/filter-class&gt;
        &lt;init-param&gt;
            &lt;description&gt;Add an Expires Header&lt;/description&gt;
            &lt;param-name&gt;header&lt;/param-name&gt;
            &lt;param-value&gt;Expires: Thu, 15 Apr 2010 20:00:00 GMT&lt;/param-value&gt;
        &lt;/init-param&gt;
        &lt;/filter&gt;
    &lt;filter-mapping&gt;
        &lt;filter-name&gt;HeaderFilter&lt;/filter-name&gt;
        &lt;url-pattern&gt;*.jpg&lt;/url-pattern&gt;
        &lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;
    &lt;/filter-mapping&gt;
&lt;/pre&gt;

This filter add the following Expires header to all jpg files, telling the browser that this response won't be stale until April 15, 2010. : 
&lt;ul&gt;
&lt;li&gt;Expires: Thu, 15 Apr 2010 20:00:00 GMT&lt;/li&gt;
&lt;/ul&gt;
You can test the client side with FireFox plugins like FireBug and Yslow :
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_rToRrTc9Ywo/SGQeU5Yno7I/AAAAAAAABxo/5771Sqy5WV8/s1600-h/Expire-header.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_rToRrTc9Ywo/SGQeU5Yno7I/AAAAAAAABxo/5771Sqy5WV8/s320/Expire-header.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5216327612752176050" /&gt;&lt;/a&gt;
&lt;a href="http://developer.yahoo.com/performance/" &gt; I encourage you to read all the bests practices !&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-2228559460414596379?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/2228559460414596379/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=2228559460414596379" title="8 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/2228559460414596379?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/2228559460414596379?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/RCZX-dqYdvQ/tomcat-add-expires-header.html" title="Tomcat : Add an Expires Header" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_rToRrTc9Ywo/SGQeU5Yno7I/AAAAAAAABxo/5771Sqy5WV8/s72-c/Expire-header.png" height="72" width="72" /><thr:total>8</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/06/tomcat-add-expires-header.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEMSX49fip7ImA9WxdWEkg.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-8791040551804258273</id><published>2008-05-15T12:32:00.006+02:00</published><updated>2008-07-05T12:11:28.066+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-05T12:11:28.066+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="hibernate" /><category scheme="http://www.blogger.com/atom/ns#" term="REST" /><category scheme="http://www.blogger.com/atom/ns#" term="jersey" /><title>Jersey (JSR-311) + Hibernate</title><content type="html">&lt;a href="https://jersey.dev.java.net/"&gt;Jersey (0.7 EA)&lt;/a&gt; requires the 'asm-3.1.jar' to work but Hibernate core (3.2) already uses another version of that library : asm-attrs.jar, asm.jar and cglib-2.1.3.jar.
&lt;p&gt;
To fix this issue you have to download the no-dependencies version of cglib &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=56933&amp;amp;package_id=98218&amp;amp;release_id=363136"&gt;here&lt;/a&gt; and replace the cglib-2.1.3.jar file by the cglib-nodep-2.1_3.jar. After, you can remove the asm-attrs.jar, asm.jar jars and add the jersey.jar, jsr311-api.jar, asm-3.1.jar in your lib directory.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-8791040551804258273?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/8791040551804258273/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=8791040551804258273" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/8791040551804258273?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/8791040551804258273?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/FYpkQeieTlU/jersay-jsr-311-hibernate.html" title="Jersey (JSR-311) + Hibernate" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/05/jersay-jsr-311-hibernate.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIFQXY5cSp7ImA9WxdWEkg.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-1307018554759639494</id><published>2008-05-13T13:36:00.013+02:00</published><updated>2008-07-05T12:08:30.829+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-05T12:08:30.829+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="REST" /><category scheme="http://www.blogger.com/atom/ns#" term="jersey" /><title>Java : Easy REST</title><content type="html">A REST xml web service is a good candidate to deal with a RIA like a Flex client.
But create a servlet that parses the request URI path is not an efficient way to build a REST resource. it's painful...
Hey, Do you know the JSR-311 ? No ! it's the most easy way to create a REST resource,  just adding some annotations to your methods, like this :
&lt;pre class="java" name="code"&gt;
@GET
@ProduceMime("application/xml")
public Product getProduct(@PathParam("id")
Integer id) {
   // Get the product ...
   return product;
}
&lt;/pre&gt;

In this case the method must be invoke by a GET HTTP request, the response will have the content type 'application/xml' and returns some xml content.
To invoke this web method you have to call the following URL :
&lt;li&gt;http://mydomain/webcontext/resource_path/param1&lt;/li&gt;

&lt;h3&gt;Setup Jersey&lt;/h3&gt;
&lt;a href="https://jersey.dev.java.net/"&gt;Jersey&lt;/a&gt; is the reference implementation of the JSR-311, the lastest stable release is provided with lots of examples.  If you use netbeans 6.1 you can create and integrate a REST resource with Jersey easily.

The core installation required only 3 jars : 
&lt;li&gt;jersey.jar, jsr311-api.jar, asm-3.1.jar&lt;/li&gt;

And you need to declare a servlet in your web.xml :
&lt;pre class="xml" name="code"&gt;
 &lt;servlet&gt;
     &lt;servlet-name&gt;ServletAdaptor&lt;/servlet-name&gt;
     &lt;servlet-class&gt;com.sun.ws.rest.impl.container.servlet.ServletAdaptor&lt;/servlet-class&gt;
     &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
 &lt;/servlet&gt;
 &lt;servlet-mapping&gt;
     &lt;servlet-name&gt;ServletAdaptor&lt;/servlet-name&gt;
     &lt;url-pattern&gt;/resource/*&lt;/url-pattern&gt;
 &lt;/servlet-mapping&gt;
&lt;/pre&gt;

Play with jersey, you'll love it :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-1307018554759639494?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/1307018554759639494/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=1307018554759639494" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/1307018554759639494?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/1307018554759639494?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/Y_eWnYLDOzE/java-easy-rest.html" title="Java : Easy REST" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/05/java-easy-rest.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEECSXw7cSp7ImA9WxdWEkg.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-4307199441874789099</id><published>2008-04-22T13:46:00.011+02:00</published><updated>2008-07-05T12:11:08.209+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-05T12:11:08.209+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="collection" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="hibernate" /><category scheme="http://www.blogger.com/atom/ns#" term="enums" /><title>Hibernate + mapping + Java enums collection.</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_rToRrTc9Ywo/SA3T9BEfeVI/AAAAAAAABug/EpKnIpZilb8/s1600-h/many_to_one.png" class="snap_noshots"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_rToRrTc9Ywo/SA3T9BEfeVI/AAAAAAAABug/EpKnIpZilb8/s320/many_to_one.png" alt="" id="BLOGGER_PHOTO_ID_5192038990640806226" border="0" /&gt;&lt;/a&gt;
Hey, can you replace this select box by checks boxes in this web form ?
Hum .... I have already mapped this combo box to an enum in my hibernate entity mapping. I must change that property to a set of enums (ManyToOne relation) :
&lt;pre class="java" name="code"&gt;
@Enumerated(EnumType.STRING)
@Column(name="color")
private ColorEnum color = ColorEnum.RED;
&lt;/pre&gt;
to
&lt;pre class="java" name="code"&gt;
@CollectionOfElements
@JoinTable( name="item_colors",joinColumns={@JoinColumn(name="item_id")}           )
@Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@Enumerated(value=EnumType.STRING)
@Column( name="color", length=25 )
private Set&amp;lt;ColorEnum&amp;gt; colors = new LinkedHashSet&amp;lt;ColorEnum&amp;gt;();
&lt;/pre&gt;In the previous mapping the color property was mapped on a simple VARCHAR(25) of the item table. And in the second case i created a new table (MySQL) like this :

&lt;pre class="sql" name="code"&gt;
CREATE TABLE `item_colors` (
`item_id` INT NOT NULL,
`color` VARCHAR(25) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`item_id`, `color`)
)
CHARACTER SET utf8;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-4307199441874789099?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/4307199441874789099/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=4307199441874789099" title="3 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/4307199441874789099?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/4307199441874789099?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/VWcdTby5cLo/hibernate-map-collectio-of-java-enums.html" title="Hibernate + mapping + Java enums collection." /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_rToRrTc9Ywo/SA3T9BEfeVI/AAAAAAAABug/EpKnIpZilb8/s72-c/many_to_one.png" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/04/hibernate-map-collectio-of-java-enums.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMMQX07fyp7ImA9WxZbGEs.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-2078362789726579599</id><published>2008-03-24T22:45:00.006+01:00</published><updated>2008-04-22T14:31:20.307+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-22T14:31:20.307+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="flex" /><category scheme="http://www.blogger.com/atom/ns#" term="mobile" /><category scheme="http://www.blogger.com/atom/ns#" term="wurfl-browser" /><category scheme="http://www.blogger.com/atom/ns#" term="database" /><title>WURFL Browser</title><content type="html">&lt;a class="snap_noshots" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_rToRrTc9Ywo/R-gl3cvVbmI/AAAAAAAABpU/VOweGopBp94/s1600-h/wurfl_browser_V0_1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_rToRrTc9Ywo/R-gl3cvVbmI/AAAAAAAABpU/VOweGopBp94/s400/wurfl_browser_V0_1.png" alt="" id="BLOGGER_PHOTO_ID_5181433005827518050" border="0" /&gt;&lt;/a&gt;
Hey ! Do you know &lt;a href="http://wurfl.sf.net/"&gt;WURFL&lt;/a&gt; ? No ! it's an open source mobile devices database :-)
&lt;blockquote style="font-style: italic;"&gt;       The WURFL is an XML configuration file which contains information     about capabilities and features of many mobile devices.&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;This component is often a centric component for companies that deliver mobile contents to the mobile carriers or  end users (maybe you). Wurfl is a big XML file, it's not very easy to browse it with a text editor. Then i created a little Flex app to browse the Wurfl repository. You can checkout the code from the google code project &lt;a href="http://code.google.com/p/flex-wurfl-browser/"&gt;flex-wurfl-browser&lt;/a&gt; or try the demo &lt;a href="http://flex-wurfl-browser.googlecode.com/svn/trunk/trunk/wurfl-browser/demo/wurfl.html"&gt;here&lt;/a&gt;.
It's an alpha version, that embeds a wurfl XML file in the &lt;span style="font-style: italic;"&gt;assets&lt;/span&gt; directory. Please &lt;a href="http://flex-wurfl-browser.googlecode.com/svn/trunk/trunk/wurfl-browser/demo/wurfl.html"&gt;try-it&lt;/a&gt; and give me your feedback :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-2078362789726579599?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/2078362789726579599/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=2078362789726579599" title="1 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/2078362789726579599?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/2078362789726579599?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/UqH2MESEgt0/wurlfl-browser.html" title="WURFL Browser" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_rToRrTc9Ywo/R-gl3cvVbmI/AAAAAAAABpU/VOweGopBp94/s72-c/wurfl_browser_V0_1.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/03/wurlfl-browser.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEEQ308fip7ImA9WxdWEkg.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-5368224990686936607</id><published>2008-02-15T23:17:00.018+01:00</published><updated>2008-07-05T12:10:02.376+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-05T12:10:02.376+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="framework" /><category scheme="http://www.blogger.com/atom/ns#" term="xml" /><category scheme="http://www.blogger.com/atom/ns#" term="jaxb" /><title>JAXB XML customizations</title><content type="html">JAXB est un outil fantastique qui offre un bon contrôle sur la manière dont vos objets vont-être transformer (marshal) en XML. Il suffit pour cela d'annoter vos classes. 
Voici un exemple simple d'une classe 'Product' annotée avec jaxb :
&lt;pre name="code" class="java"&gt;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Product {

@XmlAttribute
private Long id;

@XmlAttribute
private String name;


public Product(){

}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}
&lt;/pre&gt;

La représentation XML de 'Product' est la suivante :
&lt;pre name="code" class="xml"&gt;
&amp;lt;product name="foo" id="123"/&amp;gt;
&lt;/pre&gt;

Le code Java pour produire ce XML est aussi très simple :
&lt;pre name="code" class="java"&gt;
// Create a product
Product product = new Product();
product.setId(123);
product.setName("foo");

// Get the jaxb context.
JAXBContext context = JAXBContext.newInstance(ProductList.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(product, System.out);
&lt;/pre&gt;

Pour plus details sur JAXB je vous conseille la documentation en ligne :
&lt;ul&gt;
&lt;li&gt;https://jaxb.dev.java.net/&lt;/li&gt;
&lt;li&gt;http://java.sun.com/javaee/5/docs/tutorial/doc/bnazf.html&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;L'héritage&lt;/h3&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_rToRrTc9Ywo/R7dZzdzPpRI/AAAAAAAABmA/zycWX6WMaAQ/s1600-h/jaxb_inheritance_customization.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_rToRrTc9Ywo/R7dZzdzPpRI/AAAAAAAABmA/zycWX6WMaAQ/s400/jaxb_inheritance_customization.png" alt="" id="BLOGGER_PHOTO_ID_5167697838138696978" border="0"&gt;&lt;/a&gt;
Jouons maintenant un peu avec l'héritage pour voir comment se comporte jaxb. Voici deux nouvelles classes qui héritent de produit.
&lt;pre name="code" class="java"&gt;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class MovieProduct extends Product{

@XmlAttribute
private Long duration;

public MovieProduct(){

}

public Long getDuration() {
 return duration;
}

public void setDuration(Long duration) {
 this.duration = duration;
}

}
&lt;/pre&gt;
et
&lt;pre name="code" class="java"&gt;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class WallpaperProduct extends Product {

@XmlAttribute
private Integer width;

@XmlAttribute
private Integer height;

public Integer getWidth() {
 return width;
}

public void setWidth(Integer width) {
 this.width = width;
}

public Integer getHeight() {
 return height;
}

public void setHeight(Integer height) {
 this.height = height;
}

}
&lt;/pre&gt;

Et une nouvelle classe qui définit une liste de produits :
&lt;pre name="code" class="java"&gt;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ProductList {

@XmlAttribute
private String name;

@XmlElementRef
private List&lt;product&gt; products = new LinkedList&lt;product&gt;();

public ProductList(){

}

public String getName() {
 return name;
}

public void setName(String name) {
 this.name = name;
}

public List&lt;product&gt; getProducts() {
 return products;
}

public void setProducts(List&lt;product&gt; products) {
 this.products = products;
}

}
&lt;/product&gt;&lt;/product&gt;&lt;/product&gt;&lt;/product&gt;&lt;/pre&gt;

Par defaut si on créé une instance de JAXBContext comme ci dessous :
&lt;pre name="code" class="java"&gt;
// Create 2 products
MovieProduct inTheMoonForLove =  new MovieProduct();
inTheMoonForLove.setId(1L);
inTheMoonForLove.setName("In the moon for love");

WallpaperProduct tuxLogo = new WallpaperProduct();
tuxLogo.setId(2L);
tuxLogo.setName("Tux !");
tuxLogo.setWidth(128);
tuxLogo.setHeight(128);

// Create a new product list
ProductList productList = new ProductList();
productList.setName("My favorite product list");
productList.getProducts().add(tuxLogo);
productList.getProducts().add(inTheMoonForLove);


// Get the jaxb context.
JAXBContext context = JAXBContext.newInstance(ProductList.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(productList, System.out);
&lt;/pre&gt;
On obtient le XML suivant :
&lt;pre&gt;
&amp;lt;productlist name="My favorite product list"&amp;gt;
&amp;lt;product name="Tux !" id="2"/&amp;gt;
&amp;lt;product name="In the moon for love" id="1"/&amp;gt;
&amp;lt;/productlist&amp;gt;
&lt;/pre&gt;

Mais ou sont passés les éléments MovieProduct et WallpaperProduct ? Pour les faire apparaître il faut ajouter les nouvelles classes qui héritent de Product au JAXBContext comme ci dessous :-)
&lt;pre name="code" class="java"&gt;
// Get the jaxb context.
JAXBContext context = JAXBContext.newInstance(ProductList.class,MovieProduct.class,WallpaperProduct.class);
&lt;/pre&gt;
Et voici le résultat :
&lt;pre name="code" class="xml"&gt;
&amp;lt;productlist name="My favorite product list"&amp;gt;
&amp;lt;wallpaperproduct height="128" width="128" name="Tux !" id="2"/&amp;gt;
&amp;lt;movieproduct name="In the moon for love" id="1"/&amp;gt;
&amp;lt;/productlist&amp;gt;
&lt;/pre&gt;
Pour plus de détails lisez ce post :
http://weblogs.java.net/blog/kohsuke/archive/2006/04/why_doesnt_jaxb.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-5368224990686936607?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/5368224990686936607/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=5368224990686936607" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/5368224990686936607?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/5368224990686936607?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/j2TVOugz-Rk/jaxb-xml-customizations.html" title="JAXB XML customizations" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_rToRrTc9Ywo/R7dZzdzPpRI/AAAAAAAABmA/zycWX6WMaAQ/s72-c/jaxb_inheritance_customization.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/02/jaxb-xml-customizations.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUAGSH07cSp7ImA9WxZQEUw.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-6911459419951734671</id><published>2008-02-15T22:27:00.006+01:00</published><updated>2008-02-15T23:15:29.309+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-15T23:15:29.309+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mod_jk" /><category scheme="http://www.blogger.com/atom/ns#" term="vhost" /><category scheme="http://www.blogger.com/atom/ns#" term="connector" /><category scheme="http://www.blogger.com/atom/ns#" term="tomcat" /><title>Tomcat + mod_jk 1.2.26 + vhost</title><content type="html">Phew !!! Today i have installed a tomcat server on my new staging env. This operation have no secret for me, i have already installed and configured many tomcat servers. But today my new tomcat server doesn't want to communicate with my apache server. I have configured my JK connector and the mod_jk configuration in the httpd.conf. After that i defined some worker and map some URI.
&lt;pre&gt;
# Where to find workers.properties
   JkWorkersFile /etc/httpd/conf/workers.properties
   # Where to put jk shared memory
   JkShmFile     /var/log/httpd/mod_jk.shm
   # Where to put jk logs
   JkLogFile     /var/log/httpd/mod_jk.log
   # Set the jk log level [debug/error/info]
   JkLogLevel    info
   # Select the timestamp log format
   JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
   # Static files in all Tomcat webapp context directories are served by apache
   JkAutoAlias /opt/tomcat/webapps
   # Add the jkstatus mount point
   JkMount /jkmanager/* jkstatus
   # Load mount points
   JKMountFile /opt/tomcat/conf/uriworkermap.properties
&lt;/pre&gt;

I have also defined a virtualhost in my apache conf. But when i tried to access to the URL the response was always a 404 http error ??!
In fact there is a big change in mod_jk 1.2.26 ! If you want all vhost to inherit mounts from the main server, you can set JkMountCopy to 'All' in the main server.

&lt;pre&gt;
JkMountCopy All
&lt;/pre&gt;

see http://tomcat.apache.org/connectors-doc/reference/apache.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-6911459419951734671?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/6911459419951734671/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=6911459419951734671" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/6911459419951734671?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/6911459419951734671?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/iWZAFsFhH9s/tomcat-modjk-1226.html" title="Tomcat + mod_jk 1.2.26 + vhost" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/02/tomcat-modjk-1226.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEGSHw6eCp7ImA9WxdWEkg.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-8686438037449081226</id><published>2008-01-25T11:14:00.002+01:00</published><updated>2008-07-05T12:10:29.210+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-05T12:10:29.210+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="hibernate" /><title>Hibernate read only query</title><content type="html">Here an example of a read only Hibernate query :
&lt;pre class="java" name="code"&gt;
  // Create a new session factory if no one exists
  // and return the current session.
  Session session = HibernateUtil.getCurrentSession();

  // Begin a new transaction.
  Transaction tx = null;
  try {
   tx = session.beginTransaction();
   // Entities retrieved by this query will be loaded in a read-only
            // mode where Hibernate will never dirty-check them or make changes
   // persistent.
   List readOnlyProductList = session.createQuery(
     "select p from Product").setReadOnly(true).list();
   
   // You can also set an entity to read-only :
   // session.setReadOnly(product,trye);

   // Do some operations ...

   // Commit changes
   tx.commit();

  } catch (Exception e) {
   // Rollback changes
   if (tx != null)
    tx.rollback();
   throw e;
  } finally {
   // Close the session.
   session.close();
  }

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-8686438037449081226?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/8686438037449081226/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=8686438037449081226" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/8686438037449081226?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/8686438037449081226?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/OlIs37LjKWw/hibernate-read-only-query.html" title="Hibernate read only query" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/01/hibernate-read-only-query.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EBRH87cSp7ImA9WB9aEko.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-7092065609659702413</id><published>2008-01-02T11:56:00.000+01:00</published><updated>2008-01-02T12:00:55.109+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-01-02T12:00:55.109+01:00</app:edited><title>Happy new year !</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_rToRrTc9Ywo/R3tuzUtkIQI/AAAAAAAABlI/adQY8Xhgwtc/s1600-h/cellfish_happy_new_year.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_rToRrTc9Ywo/R3tuzUtkIQI/AAAAAAAABlI/adQY8Xhgwtc/s400/cellfish_happy_new_year.gif" alt="" id="BLOGGER_PHOTO_ID_5150832426840498434" border="0" /&gt;&lt;/a&gt;
Bonne Année 2008 à tous !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-7092065609659702413?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/7092065609659702413/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=7092065609659702413" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/7092065609659702413?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/7092065609659702413?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/0_nIbWpPR_I/happy-new-year.html" title="Happy new year !" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_rToRrTc9Ywo/R3tuzUtkIQI/AAAAAAAABlI/adQY8Xhgwtc/s72-c/cellfish_happy_new_year.gif" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/01/happy-new-year.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIAQHs9cCp7ImA9WxdWEkg.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-3003009747096941040</id><published>2008-01-02T11:23:00.002+01:00</published><updated>2008-07-05T12:09:01.568+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-05T12:09:01.568+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="php" /><category scheme="http://www.blogger.com/atom/ns#" term="database" /><title>PHP + innodb + utf8</title><content type="html">Il m'arrive de faire des scripts PHP pour exporter des données. Et à chaque fois je suis surpris par le paradoxe de ce langage ! PHP c'est simple, puissant mais bordelique ! C'est un peu comme un pouding, ça donne envie, et c'est pas cher, alors on se goinfre et après on a mal au ventre et on le regrette. (Franchement je préfère Ruby !)


Dans mon dernier script je devais lire les données contenues dans une table Mysql innodb en utf8 pour générer un flux xml. J'ai terminé le script en 30 minutes mais suprise le fichier xml produit contenait des caratères non utf8 ?!  J'ai passé 20 minutes à tester différentes solutions d'encoding ou de configuration de la connexion à Mysql pour arriver à la solution suivante qui est de forcer le client mysql en utf8 :

&lt;pre name="code" class="ruby"&gt;
//Force default client encoding
mysql_query("SET NAMES utf8");
&lt;/pre&gt;

Beaucoup de personnes m'ont dit ne pas avoir ce pb avec leur version de PHP donc voici les details de ma configuration pour reproduire le problème :

La version de PHP sur mon Mac OSX Tiger :
&lt;pre&gt;
:~ welcome$ php -v
PHP 4.4.7 (cli) (built: Jul 10 2007 15:27:28)
Copyright (c) 1997-2007 The PHP Group
Zend Engine v1.3.0, Copyright (c) 1998-2004 Zend Technologies
&lt;/pre&gt;


La conf de Mysql :
&lt;pre&gt;
[mysqld]
#If no specific storage engine/table type is defined in an SQL-Create statement the default type will be used.
default-storage-engine=innodb
#Set the default character set.
default-character-set=utf8
&lt;/pre&gt;

Une table de test pour reproduire le pb :
&lt;pre&gt;
CREATE TABLE `test`.`test_encoding` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255),
PRIMARY KEY (`id`)
)
ENGINE = InnoDB
CHARACTER SET utf8;

INSERT INTO test_encoding (name) VALUES ('éàûôâç');
&lt;/pre&gt;


Et un script php pour tester le client :
&lt;pre name="code" class="ruby"&gt;

$link = mysql_connect("127.0.0.1", "root", "")
   or die("Impossible de se connecter : " . mysql_error());

if (!mysql_select_db('test', $link)) {
   echo 'Sélection de base de données impossible';
   exit;
}

//Force default client encoding
//mysql_query("SET NAMES utf8");

$sql    = 'SELECT * FROM test_encoding';
$result = mysql_query($sql, $link);

if (!$result) {
   echo "Erreur DB, impossible d'effectuer une requête\n";
   echo 'Erreur MySQL : ' . mysql_error();
   exit;
}

while ($row = mysql_fetch_assoc($result)) {
   echo $row['name']."\n";
}

mysql_free_result($result);

mysql_close($link);

&lt;/pre&gt;

Quand on ne force pas l'encoding du client, php semble récupérer les données utf8 du serveur en latin1. J'adore les pb d'encoding :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-3003009747096941040?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/3003009747096941040/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=3003009747096941040" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/3003009747096941040?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/3003009747096941040?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/VK-B0QC3pr8/php-innodb-utf8.html" title="PHP + innodb + utf8" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2008/01/php-innodb-utf8.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEARX85fCp7ImA9WxdWEkg.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-9145035783438131358</id><published>2007-12-21T21:41:00.002+01:00</published><updated>2008-07-05T12:10:44.124+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-05T12:10:44.124+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="hibernate" /><title>Hibernate + IndexColumn</title><content type="html">Hier, un ami m'a contacté pour me parler d'un problème de mapping avec Hibernate.
Il essayait de créer une entité &lt;span style="font-weight: bold;"&gt;Node&lt;/span&gt; avec une propriété &lt;span style="font-style: italic;"&gt;parent&lt;/span&gt; et une collection indexée &lt;span style="font-style: italic;"&gt;children&lt;/span&gt; du même type. En se basant sur la documentation des annotations hibernate il était arrivé au mapping suivant :

&lt;pre name="code" class="java"&gt;
@Entity
@Table(name="node")
public class Node {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@OneToMany(mappedBy="parent", cascade=CascadeType.ALL)
@org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@org.hibernate.annotations.IndexColumn(name="child_position")
private List&lt;node&gt; children = new ArrayList&lt;node&gt;();

@ManyToOne
@JoinColumn(name="parent_id")
private Node parent;

//...
}
&lt;/node&gt;&lt;/node&gt;&lt;/pre&gt;
&lt;p&gt;
Malheureusement quand il essayait de rendre persistent un noeud principal avec 2 enfants, hibernate lui  renvoyait l'erreur suivante : &lt;span style="font-style: italic;"&gt;org.hibernate.HibernateException: null index column for collection&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Le problème vient du fait que la collection indexée &lt;span style="font-style: italic;"&gt;children&lt;/span&gt; n'est pas mise à jour quand un noeud enfant est ajouté au noeud principal. C'est normal puisque la relation OneToMany à l'attribut mappedBy = "parent" qui est équivalent à "inverse=true" dans un fichier hbm.xml : c'est donc le coté &lt;span style="font-style: italic;"&gt;parent&lt;/span&gt; qui est responsable de la relation.
&lt;/p&gt;


Voici un workaround pour ce type de mapping :
&lt;pre name="code" class="java"&gt;
@Entity
@Table(name = "nodes")
public class Node implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Integer Id;

  private String name;

  @ManyToOne
  @JoinColumn(name = "parent_id", insertable=false, updatable=false)
  private Node parent;

  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name = "parent_id")
  @org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
  @org.hibernate.annotations.IndexColumn(name = "child_position")
  private List&lt;node&gt; children = new LinkedList&lt;node&gt;();

//...
}
&lt;/node&gt;&lt;/node&gt;&lt;/pre&gt;
&lt;p&gt;
Dans cette version l'attribut "mappedBy" a été supprimé et les attributs "insertable=false" et "updatable=false" ont été ajoutés à l'annotation @JoinColumn du coté ManyToOne. C'est donc le côté OneToMany qui est responsable de la relation bi-directionnelle ( parent &lt;-&gt; enfants). Cette manipulation revient à mettre l'attribut "inverse=false" dans un ficher hbm.xml sur le côté ManyToOne.
&lt;/p&gt;
&lt;p&gt;
Hibernate c'est pas toujours simple :-) Je me demande comment on fait ce type de mapping avec Rails et Active Records.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-9145035783438131358?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/9145035783438131358/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=9145035783438131358" title="2 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/9145035783438131358?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/9145035783438131358?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/IEOGRoEb2Ug/hibernate-index-column.html" title="Hibernate + IndexColumn" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/12/hibernate-index-column.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkQNR3g9eip7ImA9WB9bEEs.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-6159449335287700132</id><published>2007-12-19T13:35:00.000+01:00</published><updated>2007-12-19T13:46:36.662+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-12-19T13:46:36.662+01:00</app:edited><title>Une bonne présentation</title><content type="html">Personnellement, ça fait longtemps que je n'utilise plus powerpoint pour mes présentations. Je lui préfére de loin Keynotes sous Mac, il suffit de voir les présentations de Steve Jobs pour s'en convaincre :-) Alors si vous voulez faire comme Steve ne manquer cette présentation :
&lt;div style="width: 425px; text-align: left;" id="__ss_85551"&gt;&lt;object style="margin: 0px;" height="355" width="425"&gt;&lt;param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=death-by-powerpoint4344"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=death-by-powerpoint4344" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="355" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;"&gt;&lt;a href="http://www.slideshare.net/?src=embed"&gt;&lt;img src="http://static.slideshare.net/swf/logo_embd.png" style="border: 0px none ; margin-bottom: -5px;" alt="SlideShare" /&gt;&lt;/a&gt; | &lt;a href="http://www.slideshare.net/thecroaker/death-by-powerpoint" title="View 'Death by PowerPoint' on SlideShare"&gt;View&lt;/a&gt; | &lt;a href="http://www.slideshare.net/upload"&gt;Upload your own&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-6159449335287700132?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/6159449335287700132/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=6159449335287700132" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/6159449335287700132?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/6159449335287700132?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/n3sdfSB3H7A/la-mort-du-powerpoint.html" title="Une bonne présentation" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/12/la-mort-du-powerpoint.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcMRHk_fip7ImA9WB9UEU4.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-2251153149846693109</id><published>2007-12-08T18:34:00.000+01:00</published><updated>2007-12-08T18:48:05.746+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-12-08T18:48:05.746+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="conf" /><category scheme="http://www.blogger.com/atom/ns#" term="paris" /><title>ParisOnRails</title><content type="html">&lt;img src="http://paris.onrails.info/images/icones/tetiere-v2.jpg" alt="ParisOnRails" /&gt;
Je serai à la conférence &lt;a href="http://paris.onrails.info/"&gt;ParisOnRails&lt;/a&gt; le lundi 10 décembre.
J'espère que je vais en apprendre plus sur les applications rails dans le monde réel : productivity, hosting, performances, and jruby :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-2251153149846693109?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/2251153149846693109/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=2251153149846693109" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/2251153149846693109?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/2251153149846693109?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/0sg5z0JzjME/parisonrails.html" title="ParisOnRails" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/12/parisonrails.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYNQH4yeip7ImA9WB9QEU8.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-6978751583691836366</id><published>2007-10-23T08:58:00.000+02:00</published><updated>2007-10-23T10:13:11.092+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-10-23T10:13:11.092+02:00</app:edited><title>Hibernate Search and Null value</title><content type="html">&lt;p&gt;
&lt;a href="http://www.hibernate.org/"&gt;Hibernate Search&lt;/a&gt; permet d'indexer les propriétés et les relations de vos POJO dans un index Lucene pour faire des recherches à la Google. J'ai récemment utilisé Hibernate Search pour indexer des tags et leurs traductions. Dans mon modèle l'objet traduction avec la propriété language == 'null' est la traduction par defaut du tag. Problème ! &lt;a href="http://lucene.apache.org/"&gt;Lucene&lt;/a&gt; ne peut pas indexer un objet null.&lt;br/&gt; La solution est d'écrire un &lt;i&gt;custom fieldbridge&lt;/i&gt; pour indexer la propriété &lt;i&gt;language&lt;/i&gt; et définir une valeur par défaut pour la valeur &lt;span style="font-style: italic;"&gt;null&lt;/span&gt;.
&lt;/p&gt;
&lt;p&gt;
J'ai alors proposé une &lt;a href="http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-115?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel"&gt;amélioration&lt;/a&gt;  au committers d'Hibernate Search: spécifier une valeur par défault dans l'annotation @Field pour les valeurs &lt;span style="font-style: italic;"&gt;null&lt;/span&gt;.
&lt;/p&gt;
&lt;br/&gt;
Voici mon POJO TagTranslation annoté avec Hibernate Search:
&lt;pre name="code" class="java"&gt;
@Entity()
@Table(name="indexing_tag_trans")
@org.hibernate.annotations.Cache(usage=org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE)
@Indexed
public class TagTranslation implements java.io.Serializable {


private static final long serialVersionUID = -1065316566731456110L;

  @Id
  @GeneratedValue(strategy=GenerationType.IDENTITY)
  @DocumentId
  private Integer id;

  @Field(index=Index.UN_TOKENIZED, store=Store.NO)
  private String language;

  @Field(index=Index.TOKENIZED, store=Store.YES)
  private String value;

  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
  @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
  @JoinColumn(name="translation_id")
  @IndexedEmbedded
  private List&lt;tagvariation&gt; variations = new LinkedList&lt;tagvariation&gt;();


  public TagTranslation() { }
...
&lt;/tagvariation&gt;&lt;/tagvariation&gt;&lt;/pre&gt;

La nouvelle version de @Field pourrait être :

&lt;pre name="code" class="java"&gt;
  @Field(index=Index.UN_TOKENIZED, store=Store.NO, nullValue="DEFAULT")
  private String language;
&lt;/pre&gt;


La bonne nouvelle vient de tomber ce matin dans ma mail box :
&lt;pre style="overflow:scroll"&gt;
Emmanuel Bernard updated HSEARCH-115:
-------------------------------------

   Fix Version/s: 3.1.0
                  3.0.1

I don't know the impact, but we should at least introduce that to 3.1.0
&lt;/pre&gt;
&lt;p style="text-align:center"&gt;
&lt;b&gt;COOOOOOOOOOOOL !&lt;/b&gt;
&lt;/p&gt;
&lt;span&gt;
Déjà qu'Emmanuel Bernard n'avait répondu en moins d'une heure pour me fournir un workaround (le custom fieldbridge) ! Bravo, Emmanuel et aussi à toute l'équipe d'Hibernate pour votre réactivité et la qualité de votre travail !
&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-6978751583691836366?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/6978751583691836366/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=6978751583691836366" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/6978751583691836366?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/6978751583691836366?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/MRfHH8vW-TQ/hibernate-search-and-null-value.html" title="Hibernate Search and Null value" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/10/hibernate-search-and-null-value.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkIAQnk-fip7ImA9WB5aGEQ.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-4265129328255738028</id><published>2007-09-15T22:43:00.000+02:00</published><updated>2007-09-16T01:22:23.756+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-09-16T01:22:23.756+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="validator" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="hibernate" /><category scheme="http://www.blogger.com/atom/ns#" term="struts" /><title>Struts and Hibernate Validator</title><content type="html">&lt;span&gt;
Dans de nombreuses applications web la validation des données est assurée par un MVC coté serveur. C'est le cas de beaucoup d'applications web Java sous Struts v1.x : la validation des données soumises par l'utilisateur  passe par la methode validate d'un objet ActionForm ou directement dans l'action. Une alternative est d'utiliser &lt;a href="http://www.hibernate.org/412.html"&gt;Hibernate Validator&lt;/a&gt; pour valider les objets de votre modèle avant de les rendre persistants. Cette approche permet de découpler la validation du MVC et ainsi de réutiliser vos règles de validation, comme par exemple dans une version standalone de votre application.


Voici un exemple de validation d'un formulaire avec &lt;a href="http://www.hibernate.org/412.html"&gt;Hibernate Validator&lt;/a&gt; et Struts 1.2.
&lt;/span&gt;
&lt;h4&gt;Annoter votre modèle.&lt;/h4&gt;
&lt;span&gt;
Tout d'abord vous devez annoter les propriétés de vos entités avec les annotations &lt;a href="http://www.hibernate.org/412.html"&gt;Hibernate Validator&lt;/a&gt;. Voici un exemple d'une entité Product qui doit respecter les règles suivantes pour être validé :&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;Avoir un titre de 2 caractères minimum et 200 maximum.&lt;/li&gt;
&lt;li&gt;Avoir une URL d'une preview au format JPG, GIF ou PNG.&lt;/li&gt;
&lt;li&gt;Un prix avec maximum 2 chiffres après la virgule.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre name="code" class="java:nogutter"&gt;
/**
* Product Entities
* @author juliusdev
*/
@Entity
public class Product implements java.io.Serializable {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;

@Version
private Integer version;

@Length(min=2, max=200)
@NotNull()
private String title;

@NotNull
private String description;

@NotNull()
@Pattern(regex=".*\\.(gif|jpg|png)$", flags=java.util.regex.Pattern.CASE_INSENSITIVE)
private String imageURL;

@Digits(integerDigits=10, fractionalDigits=2)
private Double price;

@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name="categorized_product")
private List&lt;category&gt; categories = new LinkedList&lt;category&gt;();

/** Creates a new instance of Product */
public Product() {
}
/* Setters/Getters ...*/
}
&lt;/category&gt;&lt;/category&gt;&lt;/pre&gt;
&lt;h4&gt;Intégrer Hibernate Validator à Struts&lt;/h4&gt;
&lt;span&gt;
Dans mon exemple j'utilise la méthode validate d'un ActionForm pour valider les données du formulaire. Je vous passe les details de la configuration Struts, c'est pas le sujet. Voici le code de la méthode validate de ma classe ProductForm.
&lt;/span&gt;
&lt;pre name="code" class="java:nogutter"&gt;
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request){
    ActionErrors errors = new ActionErrors();
       
    try {
    
        Product product = new Product();
        PropertyUtils.copyProperties(product,this);
    
        ClassValidator productValidator = new ClassValidator( Product.class );
        InvalidValue[] validationMessages = productValidator.getInvalidValues(product);

        for (InvalidValue error : validationMessages) {
           errors.add(ActionMessages.GLOBAL_MESSAGE,
                   new ActionMessage("errors.detail", error.getPropertyName() + ": " +error.getMessage()));
        }

    } catch (Exception e){
        errors.add(ActionMessages.GLOBAL_MESSAGE,
                    new ActionMessage("errors.general"));
        errors.add(ActionMessages.GLOBAL_MESSAGE,
                    new ActionMessage("errors.detail",e.getMessage()));
    }

    return errors;
}
&lt;/pre&gt;
&lt;span&gt;
Struts appelle la méthode validate avant de passer les données au contrôleur (l'action). La méthode validate crée un objet du modèle (Product) et le peuple avec les données de l'ActionForm. Ensuite on crée un objet ClassValidator en passant au constructeur le type de l'objet qui doit être validé. Enfin on appelle la méthode getInvalidValues pour récupérer un tableau d'objets InvalidValue contenant le nom de la propriété et le message d'erreur (vous pouvez comme dans struts personnaliser les messages d'erreur dans des fichiers de propriétés).
&lt;/span&gt;
&lt;span&gt;
Et voici le formulaire pour ajouter un produit.
&lt;/span&gt;
&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    &amp;lt;html:errors/&amp;gt;

&amp;lt;h1&amp;gt;Add a new product&amp;lt;/h1&amp;gt;
&amp;lt;html:form action="/AddProduct" &amp;gt;
    &amp;lt;label&amp;gt;Title:&amp;lt;/label&amp;gt;
    &amp;lt;html:text property="title" /&amp;gt;
    &amp;lt;br/&amp;gt;
    &amp;lt;label&amp;gt;Description:&amp;lt;/label&amp;gt;
    &amp;lt;html:textarea property="description" /&amp;gt;
     &amp;lt;br/&amp;gt;
    &amp;lt;label&amp;gt;Image URL:&amp;lt;/label&amp;gt;
    &amp;lt;html:text property="imageURL"/&amp;gt;
     &amp;lt;br/&amp;gt;
    &amp;lt;label&amp;gt;Price:&amp;lt;/label&amp;gt;
    &amp;lt;html:text property="price"/&amp;gt;
     &amp;lt;br/&amp;gt;
     &amp;lt;html:submit/&amp;gt;
&amp;lt;/html:form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;span&gt;
Finalement une page contenant le formulaire et la liste des erreurs trouvées est renvoyée à l'utilisateur pour correction comme ci-dessous.
&lt;/span&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_rToRrTc9Ywo/RuxRMg3z4jI/AAAAAAAABcw/2JXzM2_jWfk/s1600-h/Image+2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_rToRrTc9Ywo/RuxRMg3z4jI/AAAAAAAABcw/2JXzM2_jWfk/s320/Image+2.png" alt="" id="BLOGGER_PHOTO_ID_5110548952582971954" border="0" /&gt;&lt;/a&gt;

&lt;span&gt;
Vous pouvez télécharger le code et le projet Netbeans &lt;a href="http://jbrulin.free.fr/juliusdev/hibernate-validator-struts.zip"&gt;ici&lt;/a&gt;.
&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-4265129328255738028?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/4265129328255738028/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=4265129328255738028" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/4265129328255738028?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/4265129328255738028?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/68aCzV4tdlY/struts-and-hibernate-validator.html" title="Struts and Hibernate Validator" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_rToRrTc9Ywo/RuxRMg3z4jI/AAAAAAAABcw/2JXzM2_jWfk/s72-c/Image+2.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/09/struts-and-hibernate-validator.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MEQH4yeip7ImA9WB5aE0s.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-1696804574620236547</id><published>2007-09-09T21:50:00.000+02:00</published><updated>2007-09-09T22:23:21.092+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-09-09T22:23:21.092+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vacation" /><title>Le Revest : le lac du barrage</title><content type="html">&lt;div style="text-align:center;"&gt;
&lt;a href="http://picasaweb.google.fr/julien.brulin/JuliusDev/photo?authkey=VATOai-teHQ#5108291708447477298"&gt;&lt;img src="http://lh4.google.fr/julien.brulin/RuRMPnMVzjI/AAAAAAAABco/Y6omQ0CYJJs/s400/100_2282.JPG" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div style="float:right;"&gt;
&lt;a href="http://picasaweb.google.fr/julien.brulin/JuliusDev/photo?authkey=VATOai-teHQ#5108291626843098658"&gt;&lt;img src="http://lh5.google.fr/julien.brulin/RuRMK3MVziI/AAAAAAAABcc/d-iWG-Olg5g/s144/100_2273.JPG" /&gt;&lt;/a&gt;
&lt;/div&gt;
Ce matin j'ai profité de la baisse de température (24°C) pour aller faire une randonnée autour du lac du barrage au Revest à quelques kilomètres de Toulon. C'est un très beau village, surplombé par une ancienne tour de garde qui servait de refuge à la population.

Un fois au lac j'ai pu assister à un remplissage d'un hélicoptère bombardier d'eau ! Et voici la video :
&lt;object width="425" height="350"&gt; &lt;param name="movie" value="http://www.youtube.com/v/lx4sV6EvDfc"&gt; &lt;/param&gt; &lt;embed src="http://www.youtube.com/v/lx4sV6EvDfc" type="application/x-shockwave-flash" width="425" height="350"&gt; &lt;/embed&gt; &lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-1696804574620236547?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/1696804574620236547/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=1696804574620236547" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/1696804574620236547?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/1696804574620236547?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/k0N0yZASzPs/le-revest-le-lac-du-barrage.html" title="Le Revest : le lac du barrage" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/09/le-revest-le-lac-du-barrage.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEADQXo7cSp7ImA9WB5bE0k.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-7513517630061712846</id><published>2007-08-29T00:01:00.000+02:00</published><updated>2007-08-29T01:12:50.409+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-08-29T01:12:50.409+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="blogger" /><title>Blogger + syntaxhighlighter</title><content type="html">J'utilise  blogger depuis peu, et le premier problème que j'ai rencontré c'est le formatage des bloques de code dans mes articles.
Blogger ne propose pas encore de module de colorisation syntaxique :-(
Heureusement il existe de nombreux outils en ligne pour formater votre code :
&lt;ul&gt;&lt;li&gt;&lt;a href="http://formatmysourcecode.blogspot.com/"&gt;formatmysourcecode&lt;/a&gt;: formatage du code (HTML+CSS).&lt;/li&gt;&lt;li&gt;&lt;a href="http://quickhighlighter.com/"&gt;quickhighlighter.com&lt;/a&gt;: formatage + colorisation syntaxique (HTML+CSS).&lt;/li&gt;&lt;/ul&gt;Mais je n'ai pas reussi à avoir un rendu clean de mon template blogger avec ces deux outils.
En cherchant un peu plus je suis tombé sur &lt;a href="http://code.google.com/p/syntaxhighlighter/"&gt;SyntaxHighlighter&lt;/a&gt;, une lib 100% javascript de colorisation syntaxique qui supporte de nombreux langages.

Voici comment l'intégrer dans votre template blogger.
&lt;br/&gt;
&lt;br/&gt;

1-Télécharger les source du projet &lt;a href="http://code.google.com/p/syntaxhighlighter/downloads/list"&gt;ici&lt;/a&gt;.&lt;br/&gt;

2-Ajouter  les lib javascript en bas de page.&lt;br/&gt;

3-Configurer vos balises &amp;lt;pre&amp;gt;.&lt;br/&gt;

&lt;br/&gt;

Une fois les sources téléchargées, vous avez deux options : héberger les fichiers javascript sur un autre serveur accessible en http ou embarqué le code javascript dans des balises &amp;lt;script&amp;gt;. Dans mon cas j'ai choisi d'utiliser l'hébergement gratuit fourni par mon FAI pour déployer les fichiers.&lt;br/&gt;



Ensuite vous devez éditer votre template pour y intégrer le code javascript, connectez vous sur votre compte blogger, allez dans Settings &amp;gt; Template &amp;gt;  edit HTML pour afficher le code html de votre template et ajouter les lignes suivantes avant la balise &amp;lt;/body&amp;gt;.&lt;br/&gt;
&lt;span style="font-family:monospace;"&gt;
&lt;pre name="code" class="xml"&gt;&amp;lt;link href='http://www.myhosting.net/styles/SyntaxHighlighter.css' rel='stylesheet' type='text/css'/&amp;gt;
&amp;lt;script language='javascript' src='http://www.myhosting.net/scripts/shCore.js'/&amp;gt;
&amp;lt;script language='javascript' src='http://www.myhosting.net/scripts/shBrushJava.js'/&amp;gt;
&amp;lt;script language='javascript' src='http://www.myhosting.net/scripts/shBrushJScript.js'/&amp;gt;
&amp;lt;script language='javascript' src='http://www.jmyhosting.net/scripts/shBrushRuby.js'/&amp;gt;
&amp;lt;script language='javascript'&amp;gt;
dp.SyntaxHighlighter.ClipboardSwf = 'http://www.jmyhosting.net/scripts/clipboard.swf';
dp.SyntaxHighlighter.BloggerMode();
dp.SyntaxHighlighter.HighlightAll('code');
&amp;lt;/script&amp;gt;

&lt;/pre&gt;

&lt;/span&gt;Les fichiers &lt;span style="font-style: italic;"&gt;SyntaxHighlighter.css&lt;/span&gt; et &lt;span style="font-style: italic;"&gt;shCore.js&lt;/span&gt; sont requis ensuite vous ajouter les colorisations syntaxiques de votre choix disponibles dans &lt;a href="http://code.google.com/p/syntaxhighlighter/"&gt;syntaxhighlighter&lt;/a&gt;.
Voici la liste des langages supportés:
&lt;table style="border-collapse: collapse;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt;&lt;strong&gt;Language&lt;/strong&gt; &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;strong&gt;Aliases&lt;/strong&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; C++ &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;cpp&lt;/tt&gt;, &lt;tt&gt;c&lt;/tt&gt;, &lt;tt&gt;c++&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; C# &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;c#&lt;/tt&gt;, &lt;tt&gt;c-sharp&lt;/tt&gt;, &lt;tt&gt;csharp&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; CSS &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;css&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; Delphi &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;delphi&lt;/tt&gt;, &lt;tt&gt;pascal&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; Java &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;java&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; Java Script &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;js&lt;/tt&gt;, &lt;tt&gt;jscript&lt;/tt&gt;, &lt;tt&gt;javascript&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; PHP &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;php&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; Python &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;py&lt;/tt&gt;, &lt;tt&gt;python&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; Ruby &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;rb&lt;/tt&gt;, &lt;tt&gt;ruby&lt;/tt&gt;, &lt;tt&gt;rails&lt;/tt&gt;, &lt;tt&gt;ror&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; Sql &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;sql&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; VB &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;vb&lt;/tt&gt;, &lt;tt&gt;vb.net&lt;/tt&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; XML/HTML &lt;/td&gt;&lt;td style="border: 1px solid rgb(170, 170, 170); padding: 5px;"&gt; &lt;tt&gt;xml&lt;/tt&gt;, &lt;tt&gt;html&lt;/tt&gt;, &lt;tt&gt;xhtml&lt;/tt&gt;, &lt;tt&gt;xslt&lt;/tt&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;span style="font-family:monospace;"&gt;
&lt;/span&gt;Pour tester l'installation de SyntaxHighlighter créer un post en insérant un bloque de code dans une balise &amp;lt;pre&amp;gt; avec l'attribut name="code" et l'attribut class doit contenir l'alias correspondant à votre langage (cf tableau des langages) comme ci dessous :&lt;span style="font-family:monospace;"&gt;
&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;pre name="code" class="java"&amp;gt;
List&amp;lt;String&amp;gt; categories = new LinkedList&amp;lt;String&amp;gt;();
for(String categorie : categories)
System.out.println(categorie);
&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/span&gt;Et voici le resultat :&lt;span style="font-family:monospace;"&gt;
&lt;pre name="code" class="java"&gt;
List&amp;lt;String&amp;gt; categories = new LinkedList&amp;lt;String&amp;gt;();
for(String categorie : categories)
System.out.println(categorie);
&lt;/pre&gt;
&lt;/span&gt;
Very nice !&lt;span style="font-family:monospace;"&gt;
&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-7513517630061712846?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/7513517630061712846/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=7513517630061712846" title="2 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/7513517630061712846?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/7513517630061712846?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/22w6JaO9uYk/blogger-syntaxhighlighter.html" title="Blogger + syntaxhighlighter" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/08/blogger-syntaxhighlighter.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MAQXc_eCp7ImA9WB5bEUw.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-6545176434912531497</id><published>2007-08-25T23:09:00.001+02:00</published><updated>2007-08-26T11:10:40.940+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-08-26T11:10:40.940+02:00</app:edited><title>Fête de la figue et Festival de BD</title><content type="html">&lt;img src="http://lh3.google.com/julien.brulin/RtCTaXMVzeI/AAAAAAAABYY/SMzD2WNvGwE/s144/100_2205.JPG" style="margin: 0pt 10px 10px 0pt; float: left;" /&gt;
&lt;img src="http://lh6.google.com/julien.brulin/RtCTVHMVzdI/AAAAAAAABYQ/cJHwdvZTaY0/s144/100_2204.JPG" style="margin: 0pt 10px 10px 0pt; float: left;" alt="gateaux à la figue" /&gt;
&lt;p style="text-align: left;"&gt;Ce week-end c'est la fête de la figue à &lt;a href="http://maps.google.fr/maps?f=q&amp;hl=en&amp;amp;geocode=&amp;q=sollies+pont,+france&amp;amp;amp;amp;amp;ie=UTF8&amp;ll=43.194414,6.041451&amp;amp;spn=0.11914,0.233459&amp;z=12&amp;amp;iwloc=addr&amp;om=1"&gt;Sollies Pont&lt;/a&gt;, avec au programme des tonnes de produits à la figue : gateaux, confitures, saucisses, samoussa, etc ... C'est sympa, l'ambiance est bonne et les commerçants n'hésitent pas à vous faire gouter leurs spécialités. Sous un soleil écrasant les gateaux à la figue ça donne soif mais pas moyen de trouver de l'eau, les épiceries sont fermées, et comme par hasard seuls les cafés proposent des boissons fraîches ...&lt;/p&gt;&lt;p style="text-align: left;"&gt;En même temps se déroule le &lt;a href="http://www.festivalbd.com/"&gt;19éme festival de BD de&lt;/a&gt;&lt;a href="http://maps.google.fr/maps?f=q&amp;amp;amp;hl=en&amp;geocode=&amp;amp;q=sollies+ville,+france&amp;sll=43.194414,6.041451&amp;amp;sspn=0.11914,0.233459&amp;ie=UTF8&amp;amp;ll=43.182399,6.037674&amp;spn=0.119164,0.233459&amp;amp;amp;amp;amp;z=12&amp;iwloc=addr&amp;amp;om=1"&gt; Sollies Ville&lt;/a&gt;, j'en ai profité pour découvrir de nouvelles BD, et acheter une belle affiche pour décorer mon bureau.&lt;/p&gt;
&lt;img src="http://lh5.google.com/julien.brulin/RtCTd3MVzfI/AAAAAAAABYg/9KeR-BDAIYY/s400/100_2215.JPG" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-6545176434912531497?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/6545176434912531497/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=6545176434912531497" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/6545176434912531497?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/6545176434912531497?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/sJsXRVzTQXQ/festival-de-db-et-fte-de-la-figue.html" title="Fête de la figue et Festival de BD" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/08/festival-de-db-et-fte-de-la-figue.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0AGQH48eCp7ImA9WB5bEUw.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-3787256564710980569</id><published>2007-08-24T00:31:00.000+02:00</published><updated>2007-08-26T11:15:21.070+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-08-26T11:15:21.070+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="dwr" /><category scheme="http://www.blogger.com/atom/ns#" term="yui" /><category scheme="http://www.blogger.com/atom/ns#" term="ajax" /><title>YUI autocomplete + DWR Part II</title><content type="html">Voici une solution plus propre pour intégrer &lt;a href="http://getahead.org/dwr"&gt;DWR&lt;/a&gt; avec le composant &lt;span style="font-style: italic;"&gt;autocomplete&lt;/span&gt; de &lt;a href="http://developer.yahoo.com/yui/"&gt;YUI&lt;/a&gt;.
Il suffit de créer une nouvelle classe qui hérite de &lt;span style="font-style: italic;"&gt;YAHOO.widget.DataSource&lt;/span&gt;   et de surcharger la methode &lt;span style="font-style: italic;"&gt;doQuery&lt;/span&gt; de la class &lt;a href="http://developer.yahoo.com/yui/docs/YAHOO.widget.DataSource.html#doQuery"&gt;&lt;span style="font-weight: bold;"&gt;YAHOO.widget.DataSource&lt;/span&gt;&lt;/a&gt; comme dans l'exemple suivant :
&lt;pre name="code" class="js"&gt;
DwrYuiDataSource = function(remoteMethod) {
this.remoteMethod = remoteMethod;
this._init();
};

//prototype-based inheritance
DwrYuiDataSource.prototype = new YAHOO.widget.DataSource();

//override doQuery method
DwrYuiDataSource.prototype.doQuery = function(oCallbackFn, sQuery, oParent) {
var oSelf = this;
this.remoteMethod(sQuery, function(aResults) {
var resultObj = {};
resultObj.query = decodeURIComponent(sQuery);
//transform DWR response to Array of Array...
resultObj.results = objecToArray(aResults);
oSelf._addCacheElem(resultObj);    
oSelf.getResultsEvent.fire(oSelf, oParent, sQuery, aResults);
oCallbackFn(sQuery, objecToArray(aResults), oParent);
});
};

//transform object to array
function objecToArray(dataFromServer){
var aResults = [];
for (var i in dataFromServer) {
if(i != 'toJSONString')
 aResults.push([i,dataFromServer[i]]);
}
return aResults;
}
&lt;/pre&gt;

Ensuite vous pouvez utiliser cette nouvelle source de données pour créer votre autocompleter.
&lt;pre name="code" class="js"&gt;YAHOO.example.DWR = new function(){
// Instantiate DWR DataSource
this.oACDS = new DwrYuiDataSource(Demo.suggestCountries);

// Instantiate AutoComplete
this.oAutoComp = new YAHOO.widget.AutoComplete('input','container', this.oACDS);

...
&lt;/pre&gt;

Merci à &lt;a href="http://www.nabble.com/user/UserProfile.jtp?user=327929"&gt;Lance Semmens-3&lt;/a&gt; pour avoir poster cette solution sur &lt;a href="http://www.nabble.com/DWR-and-YUI-autocomplete-p12036788.html"&gt;Nabble&lt;/a&gt; !

Ps: vous pouvez télécharger le projet Netbeans contenant le code source &lt;a href="http://jbrulin.free.fr/juliusdev/yui.zip"&gt;ici&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-3787256564710980569?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/3787256564710980569/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=3787256564710980569" title="1 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/3787256564710980569?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/3787256564710980569?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/LuEy92XnE-A/yui-autocomplete-dwr-part-ii.html" title="YUI autocomplete + DWR Part II" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/08/yui-autocomplete-dwr-part-ii.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkQASXc_fip7ImA9WB5UGUg.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-1545491194352687806</id><published>2007-08-19T21:11:00.000+02:00</published><updated>2007-08-24T14:25:48.946+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-08-24T14:25:48.946+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="dwr" /><category scheme="http://www.blogger.com/atom/ns#" term="yui" /><category scheme="http://www.blogger.com/atom/ns#" term="ajax" /><title>YUI autocomplete + DWR</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_rToRrTc9Ywo/Rsi9dXMVzbI/AAAAAAAABXU/IZnVtKMJMEI/s1600-h/autocomplete_en.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_rToRrTc9Ywo/Rsi9dXMVzbI/AAAAAAAABXU/IZnVtKMJMEI/s200/autocomplete_en.png" alt="" id="BLOGGER_PHOTO_ID_5100534890136718770" border="0" /&gt;&lt;/a&gt;J'utilise &lt;a href="http://getahead.org/dwr"&gt;&lt;span id="misp_compose_1" class="hm"&gt;DWR&lt;/span&gt;&lt;/a&gt; depuis longtemps, c'est un &lt;span id="misp_compose_2" class="hm"&gt;framework&lt;/span&gt; &lt;span id="misp_compose_3" class="hm"&gt;AJAX&lt;/span&gt; simple et efficace pour appeler des &lt;span id="misp_compose_4" class="hm"&gt;methodes&lt;/span&gt; distantes en javascript. En parallèle de &lt;a href="http://getahead.org/dwr"&gt;&lt;span id="misp_compose_5" class="hm"&gt;DWR&lt;/span&gt;&lt;/a&gt; j'utilise aussi &lt;a href="http://www.prototypejs.org/"&gt;prototype&lt;/a&gt; et &lt;a href="http://script.aculo.us/"&gt;&lt;span id="misp_compose_6" class="hm"&gt;scriptaculous&lt;/span&gt;&lt;/a&gt; dans mes pages. Il y a quelques jours on m'a demander de réaliser un composant &lt;span id="misp_compose_7" class="hm"&gt;AJAX&lt;/span&gt; pour suggérer des &lt;span id="misp_compose_8" class="hm"&gt;TAG&lt;/span&gt;, ce genre de composant est assez répandu, l'exemple le plus connu est le &lt;span id="misp_compose_9" class="hm"&gt;suggest&lt;/span&gt; de google. &lt;a href="http://script.aculo.us/"&gt;&lt;span id="misp_compose_10" class="hm"&gt;Scriptaculous&lt;/span&gt;&lt;/a&gt; propose déjà des classes &lt;span id="misp_compose_11" class="hm"&gt;d'&lt;a href="http://wiki.script.aculo.us/scriptaculous/show/Autocompletion"&gt;autocompletion&lt;/a&gt;&lt;/span&gt; : une version locale qui suggère des réponses d'un tableau javascript et une version &lt;span id="misp_compose_12" class="hm"&gt;ajax&lt;/span&gt; qui &lt;span id="misp_compose_13" class="hm"&gt;parse&lt;/span&gt; une liste html (&amp;lt;&lt;span id="misp_compose_14" class="hm"&gt;ul&lt;/span&gt;&amp;gt;&amp;lt;li&amp;gt;&lt;span id="misp_compose_15" class="hm"&gt;tag&lt;/span&gt;&amp;lt;/li&amp;gt;&amp;lt;/&lt;span id="misp_compose_16" class="hm"&gt;ul&lt;/span&gt;&amp;gt;) renvoyé par votre serveur. Bref, la classe &lt;span id="misp_compose_17" class="hm"&gt;d'auto&lt;/span&gt;&lt;span id="misp_compose_17" class="hm"&gt;complete&lt;/span&gt; &lt;span id="misp_compose_18" class="hm"&gt;ajax&lt;/span&gt; de &lt;span id="misp_compose_19" class="hm"&gt;scriptaculous&lt;/span&gt; ne permet pas passer un &lt;span id="misp_compose_20" class="hm"&gt;callback&lt;/span&gt; javascript pour appeler une méthode distante via &lt;a href="http://getahead.org/dwr"&gt;&lt;span id="misp_compose_21" class="hm"&gt;DWR&lt;/span&gt;.&lt;/a&gt;

Après quelques recherches sur net, je suis tombé sur &lt;a href="http://developer.yahoo.com/yui/autocomplete/"&gt;Yahoo &lt;span id="misp_compose_1" class="hm"&gt;ui&lt;/span&gt; (&lt;span id="misp_compose_2" class="hm"&gt;YUI&lt;/span&gt;)&lt;/a&gt;, la bibliothèque de composants de &lt;span id="misp_compose_4" class="hm"&gt;yahoo&lt;/span&gt;. C'est bien documenté, et les exemples sont nombreux, alors je me suis lancé dans un test d'intégration avec &lt;span id="misp_compose_5" class="hm"&gt;DWR&lt;/span&gt;.

Voici un &lt;span id="misp_compose_6" class="hm"&gt;bean&lt;/span&gt; &lt;span id="misp_compose_7" class="hm"&gt;DWR&lt;/span&gt; d'exemple qui contient une méthode &lt;span style="font-style: italic;"&gt;&lt;span id="misp_compose_8" class="hm"&gt;suggestCountries&lt;/span&gt;&lt;/span&gt;  qui renvoie un &lt;span id="misp_compose_9" class="hm"&gt;Map&lt;/span&gt; de code pays et
une version localisé du nom du pays.


&lt;pre name="code" class="java"&gt;
public class DWRDemo {
    
    Logger logger = Logger.getLogger(this.getClass().getName());
    
    private Locale userLocale;
    
    /** Creates a new instance of DWRDemo */
    public DWRDemo() {
        WebContext ctx = WebContextFactory.get();
        this.userLocale = ctx.getHttpServletRequest().getLocale();
    }
    
    public DWRDemo(Locale userLocale){
        this.userLocale = userLocale;
    }
    
    /**
     * Suggest a dictionary of country codes and localized country names.
     * This method search the specified string token in each localized country name.
     *@param token a string token.
     *@return a Map of countries codes and theirs localized names.
     */
    public Map&amp;lt;String,String&amp;gt; suggestCountries(String token){
        if(logger.isLoggable(Level.FINE))
            logger.fine(&amp;quot;Call suggestCountries method with token: &amp;quot; + token);
        
        Map&amp;lt;String,String&amp;gt; suggestions = new LinkedHashMap&amp;lt;String,String&amp;gt;();
        String[] countries = Locale.getISOCountries();
        // Compile regular expression
        Pattern pattern = Pattern.compile(&amp;quot;(?i)&amp;quot;+token);
        for (String country : countries) {
            String localizedCountryName = new Locale(this.userLocale.getLanguage(),country).getDisplayCountry(userLocale);
            Matcher matcher = pattern.matcher(localizedCountryName);
            if(matcher.find() &amp;amp;&amp;amp; !suggestions.containsKey(country))
                suggestions.put(country,localizedCountryName);
            
        }
        
        if(logger.isLoggable(Level.FINE))
            logger.fine(suggestions.size() + &amp;quot; countrie(s) were found.&amp;quot;);
        
        return suggestions;
    }
}

&lt;/pre&gt;


Le composant &lt;span id="misp_compose_1" class="hm"&gt;autocomplete&lt;/span&gt; de &lt;span id="misp_compose_2" class="hm"&gt;YUI&lt;/span&gt; utilise un &lt;span id="misp_compose_3" class="hm"&gt;object&lt;/span&gt; &lt;span id="misp_compose_4" class="hm"&gt;dataSource&lt;/span&gt; pour récupérer les réponses à suggérer. Il existe plusieurs types de &lt;span id="misp_compose_5" class="hm"&gt;dataSource&lt;/span&gt; qui acceptent un tableau javascript, une fonction, ou une &lt;span id="misp_compose_6" class="hm"&gt;url&lt;/span&gt; qui renvoie du &lt;span id="misp_compose_7" class="hm"&gt;json&lt;/span&gt; ou du &lt;span id="misp_compose_8" class="hm"&gt;xml&lt;/span&gt;. Dans mon cas j'ai utilisé la &lt;span id="misp_compose_9" class="hm"&gt;dataSource&lt;/span&gt; qui utilise une fonction.

&lt;pre name="code" class="js"&gt;
//populate suggestions array
function populateArray(dataFromServer, dataFromBrwoser){
 for (var i in dataFromServer) {
  dataFromBrwoser.push([i,dataFromServer[i]]);
 }
}

//call dwr remote method and returns suggestions
function getCountries(sQuery){
 var aResults = [];
 if (sQuery &amp;&amp; sQuery.length &gt; 0) {
  var callbackProxy = function(results){
     populateArray(results, aResults);
  };
  
  //disable async req !
  var callMetaData = { callback:callbackProxy,  async:false};
  //Call remote method
  Demo.suggestCountries(sQuery,callMetaData);
 }
 
 return aResults;
}

&lt;/pre&gt;
Et voici le code du composant autocomplete yui :
&lt;pre name="code" class="js"&gt;YAHOO.example.DWR = new function(){
// Instantiate JS Function DataSource
this.oACDS = new YAHOO.widget.DS_JSFunction(getCountries);

// Instantiate AutoComplete
this.oAutoComp = new YAHOO.widget.AutoComplete('input','container', this.oACDS);
this.oAutoComp.useShadow = true;
this.oAutoComp.minQueryLength = 0;
this.oAutoComp.maxResultsDisplayed = 10;
this.oAutoComp.formatResult = function(oResultItem, sQuery) {
   var sMarkup = oResultItem[1] + " ("+oResultItem[0]+")";
   return (sMarkup);
};

// Show custom message if no results found
this.myOnDataReturn = function(sType, aArgs) {
   var oAutoComp = aArgs[0];
   var sQuery = aArgs[1];
   var aResults = aArgs[2];

   if(aResults.length == 0) {
       oAutoComp.setBody("&amp;lt;div id=\"containerdefault\"&amp;gt;No matching results&amp;lt;/div&amp;gt;");
   }
};


this.itemSelectHandler = function(sType, aArgs) {
   var oMyAcInstance = aArgs[0]; // your AutoComplete instance
   var elListItem = aArgs[1]; //the &amp;lt;li&amp;gt; element selected in the suggestion
                              //container
   var aData = aArgs[2]; //array of the data for the item as returned by the DataSource
   document.getElementById('input').value = aData[1];
   document.getElementById('countrycode').value = aData[0];
};

//Register events
this.oAutoComp.dataReturnEvent.subscribe(this.myOnDataReturn);
this.oAutoComp.itemSelectEvent.subscribe(this.itemSelectHandler);

};
&lt;/pre&gt;

Et le container HTML :

&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;        &amp;lt;h3&amp;gt;Filter countries:&amp;lt;/h3&amp;gt;
&amp;lt;div id="autocomplete"&amp;gt;
&amp;lt;input id="input" type="text"&amp;gt;
&amp;lt;div id="container"&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;Mon composant fonctionne, mais il n'est pas très performant : en effet pour que la fonction &lt;span style="font-style: italic;"&gt;&lt;span id="misp_compose_1" class="hm"&gt;getCountries&lt;/span&gt;&lt;/span&gt; renvoie un tableau de résultat à chaque frappe de l'utilisateur dans l'input, &lt;a href="http://getahead.org/dwr/browser/engine/options"&gt;j'ai du désactivé l'appel asynchrone (&lt;span id="misp_compose_3" class="hm"&gt;async&lt;/span&gt;:&lt;span id="misp_compose_4" class="hm"&gt;false&lt;/span&gt;)&lt;/a&gt;.



Pour l'instant je n'ai pas trouvé un moyen plus élégant d'utiliser &lt;span id="misp_compose_6" class="hm"&gt;DWR&lt;/span&gt; et &lt;span id="misp_compose_7" class="hm"&gt;YUI&lt;/span&gt;, alors si vous avez une idée, je suis preneur :-)

Vous pouvez &lt;span id="misp_compose_8" class="hm"&gt;télécharger&lt;/span&gt; le projet &lt;span id="misp_compose_9" class="hm"&gt;netbeans&lt;/span&gt; avec le &lt;a href="http://jbrulin.free.fr/juliusdev/yui.zip"&gt;code&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-1545491194352687806?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/1545491194352687806/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=1545491194352687806" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/1545491194352687806?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/1545491194352687806?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/46UiDYcXLqY/yui-autocomplete-dwr.html" title="YUI autocomplete + DWR" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_rToRrTc9Ywo/Rsi9dXMVzbI/AAAAAAAABXU/IZnVtKMJMEI/s72-c/autocomplete_en.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/08/yui-autocomplete-dwr.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IHQ3syeCp7ImA9WB5UFkw.&quot;"><id>tag:blogger.com,1999:blog-3086643476690485109.post-7314734889886519023</id><published>2007-08-03T18:51:00.000+02:00</published><updated>2007-08-20T16:18:52.590+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-08-20T16:18:52.590+02:00</app:edited><title>Cellfish is Mobile 2.0 ?</title><content type="html">Je travaille depuis 6 ans chez &lt;a href="http://www.cellfishmedia.fr"&gt;Cellfish&lt;/a&gt; (ex:Plurimedia), cette companie est spécialisée dans la gestion de contenu et la réalisation de services mobiles. Nos principaux clients sont les opérateurs mobiles (SFR,Orange, BouyguesTelecom,....) . Il y a quelques semaines cellfish a lancé &lt;a href="http://www.cellfish.com"&gt;cellfishDotCom&lt;/a&gt; un site Web 2.0 ou plutôt Mobile 2.0 qui permet de mettre en ligne des contenus, les partagés et de créer des réseaux sociaux tout ça de votre mobile.



&lt;object width="420" height="315"&gt;&lt;param name="movie" value="http://cellfish.com/static/swf/player8.swf?Id=155282" /&gt;&lt;param name="wmode" value="window" /&gt;&lt;embed src="http://cellfish.com/static/swf/player8.swf?Id=155282" type="application/x-shockwave-flash" wmode="window" width="420" height="315" &gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3086643476690485109-7314734889886519023?l=juliusdev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://juliusdev.blogspot.com/feeds/7314734889886519023/comments/default" title="Publier les commentaires" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3086643476690485109&amp;postID=7314734889886519023" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/7314734889886519023?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3086643476690485109/posts/default/7314734889886519023?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JuliusDev/~3/hR4bSyasYn0/cellfish-is-mobile-20.html" title="Cellfish is Mobile 2.0 ?" /><author><name>julius</name><uri>http://www.blogger.com/profile/01090876422835754313</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://juliusdev.blogspot.com/2007/08/cellfish-is-mobile-20.html</feedburner:origLink></entry></feed>

