<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3086643476690485109</id><updated>2024-02-07T21:02:34.476+01:00</updated><category term="java"/><category term="hibernate"/><category term="REST"/><category term="jersey"/><category term="tomcat"/><category term="collection"/><category term="connector"/><category term="database"/><category term="enums"/><category term="framework"/><category term="jaxb"/><category term="jms"/><category term="mod_jk"/><category term="mysql"/><category term="php"/><category term="ruby"/><category term="struts"/><category term="validator"/><category term="vhost"/><category term="xml"/><title type='text'>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='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="jms"/><title type='text'>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&#39;s urls, the message is put in the the jms queue and it&#39;s dispatched to consumers (listeners). Each consumer tries to download files and save them on the disk. Pretty simple isn&#39;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=&quot;code&quot; class=&quot;java&quot;&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&#39;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 =
                &quot;Unable to open file &quot; + destination + &quot; for writing.&quot;;
            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=&quot;code&quot; class=&quot;java&quot;&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 =
                &quot;Unable to open file &quot; + destination + &quot; for writing.&quot;;
            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;</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/fullpage/post/3086643476690485109/4879326777997736276' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/4879326777997736276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/4879326777997736276'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2009/10/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="jersey"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><title type='text'>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&#39;ll use &lt;a href=&quot;http://flexjson.sourceforge.net/&quot; &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=&quot;code&quot; class=&quot;java&quot;&gt;
    @GET
    @Path(&quot;{id}&quot;)
    @ProduceMime(&quot;application/json&quot;)
    public String getJSONProduct(@PathParam(&quot;id&quot;) Integer id){
       return new JSONSerializer().exclude(&quot;*.class&quot;) // Exclude the property class from the json
                                  .include(&quot;categories&quot;)
                                  .serialize(product);
    }
&lt;/pre&gt;

See the output :
&lt;pre&gt;
curl -v -H &quot;Accept: application/json&quot; 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
{&quot;categories&quot;:[{&quot;id&quot;:1,&quot;name&quot;:&quot;mobile&quot;}],
&quot;description&quot;:&quot;A great mobile device !&quot;,
&quot;id&quot;:1,&quot;name&quot;:&quot;iphone&quot;}
&lt;/pre&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/fullpage/post/3086643476690485109/8912014506349368472' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/8912014506349368472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/8912014506349368472'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2008/07/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="jersey"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><title type='text'>Jersey REST (JSR-311) and JSON</title><content type='html'>With Jersey it&#39;s very easy to create a RESTfull resource which returns an XML version of your objects:
&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;
    @GET
    @Path(&quot;{id}&quot;)
    @ProduceMime(&quot;application/xml&quot;)
    public Product getProduct(@PathParam(&quot;id&quot;) 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=&quot;code&quot; class=&quot;java&quot;&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&#39;s try the service :
&lt;pre&gt;
curl -v -H &quot;Accept: application/xml&quot; 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=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&amp;gt;
&amp;lt;product id=&quot;1&quot;&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=&quot;code&quot; class=&quot;java&quot;&gt;
    @GET
    @Path(&quot;{id}&quot;)
    @ProduceMime({&quot;application/json&quot;,&quot;application/xml&quot;})
    public Product getProduct(@PathParam(&quot;id&quot;) 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 &quot;Accept: application/json&quot; 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
{&quot;product&quot;:{&quot;@id&quot;:&quot;1&quot;,&quot;name&quot;:&quot;myphone&quot;,
&quot;description&quot;:&quot;A great mobile device !&quot;,
&quot;category&quot;:{&quot;id&quot;:&quot;1&quot;,&quot;name&quot;:&quot;mobile&quot;}}}
&lt;/pre&gt;

It&#39;s very easy and powerful ! But if you look in details the JSON output you&#39;ll notice that the Product&#39;s property &lt;i&gt;id&lt;/i&gt; is &quot;&quot;@id&quot;:&quot;1&quot;&quot; and not &quot;&quot;id&quot;:1&quot; ?!
&lt;p&gt;
In this case the Product object is marshalling by JAXB and converted to JSON by  &lt;a href=&quot;http://jettison.codehaus.org/&quot;&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;
{&quot;product&quot;:{&quot;id&quot;:1,&quot;name&quot;:&quot;myphone&quot;}
&lt;/pre&gt; 
You have to remove all JAXB annotations from the Product classe. You&#39;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=&quot;http://juliusdev.blogspot.com/2008/07/jersey-rest-jsr-311-and-json-part-ii.html&quot;&gt;see the part II&lt;/a&gt; :-)
&lt;/p&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/fullpage/post/3086643476690485109/8930183534527973910' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/8930183534527973910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/8930183534527973910'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2008/07/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="tomcat"/><title type='text'>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=&quot;http://developer.yahoo.com/performance/rules.html#expires&quot;&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=&quot;code&quot; class=&quot;java&quot;&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(&quot;header&quot;);
        if (headerParam == null) {
            log.warn(&quot;No headers were found in the web.xml (init-param) for the HeaderFilter !&quot;);
            return;
        }

        // Init the header list :
        headersMap = new LinkedHashMap&lt;String, String&gt;();

        if (headerParam.contains(&quot;|&quot;)) {
            String[] headers = headerParam.split(&quot;|&quot;);
            for (String header : headers) {
                parseHeader(header);
            }

        } else {
            parseHeader(headerParam);
        }

        // Log configured headers .
        if (log.isInfoEnabled()) {
            log.info(&quot;The following headers were registered in the HeaderFilter :&quot;);
            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() + &#39;:&#39; + 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(&quot;:&quot;));
        if (!headersMap.containsKey(headerName)) {
            headersMap.put(headerName, header.substring(header.indexOf(&quot;:&quot;) + 1));
        }
    }
}
&lt;/pre&gt;

To use this filter in your webapp, just edit your web.xml to add this lines :

&lt;pre name=&quot;code&quot; class=&quot;xml&quot;&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&#39;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=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiURv8vJ0U2hqM4GEzf1y45EEUgELvsl7I7CMtpQXOqq1PDkY74UmbF0BdZ6pyne3dINErmjb9sxEs73Ld6Yoq2CLJhgNQOh98qRZuIrtujeCko3zuMiqJC-cYrm43HjeCsDUefLe_E4h8/s1600-h/Expire-header.png&quot;&gt;&lt;img style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiURv8vJ0U2hqM4GEzf1y45EEUgELvsl7I7CMtpQXOqq1PDkY74UmbF0BdZ6pyne3dINErmjb9sxEs73Ld6Yoq2CLJhgNQOh98qRZuIrtujeCko3zuMiqJC-cYrm43HjeCsDUefLe_E4h8/s320/Expire-header.png&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5216327612752176050&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;http://developer.yahoo.com/performance/&quot; &gt; I encourage you to read all the bests practices !&lt;/a&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/fullpage/post/3086643476690485109/2228559460414596379' title='12 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/2228559460414596379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/2228559460414596379'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2008/06/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiURv8vJ0U2hqM4GEzf1y45EEUgELvsl7I7CMtpQXOqq1PDkY74UmbF0BdZ6pyne3dINErmjb9sxEs73Ld6Yoq2CLJhgNQOh98qRZuIrtujeCko3zuMiqJC-cYrm43HjeCsDUefLe_E4h8/s72-c/Expire-header.png" height="72" width="72"/><thr:total>12</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="hibernate"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="jersey"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><title type='text'>Jersey (JSR-311) + Hibernate</title><content type='html'>&lt;a href=&quot;https://jersey.dev.java.net/&quot;&gt;Jersey (0.7 EA)&lt;/a&gt; requires the &#39;asm-3.1.jar&#39; 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=&quot;http://sourceforge.net/project/showfiles.php?group_id=56933&amp;amp;package_id=98218&amp;amp;release_id=363136&quot;&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;</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/fullpage/post/3086643476690485109/8791040551804258273' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/8791040551804258273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/8791040551804258273'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2008/05/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="jersey"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><title type='text'>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&#39;s painful...
Hey, Do you know the JSR-311 ? No ! it&#39;s the most easy way to create a REST resource,  just adding some annotations to your methods, like this :
&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;
@GET
@ProduceMime(&quot;application/xml&quot;)
public Product getProduct(@PathParam(&quot;id&quot;)
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 &#39;application/xml&#39; 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=&quot;https://jersey.dev.java.net/&quot;&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=&quot;xml&quot; name=&quot;code&quot;&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&#39;ll love it :-)</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/fullpage/post/3086643476690485109/1307018554759639494' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/1307018554759639494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/1307018554759639494'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2008/05/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="collection"/><category scheme="http://www.blogger.com/atom/ns#" term="enums"/><category scheme="http://www.blogger.com/atom/ns#" term="hibernate"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>Hibernate + mapping + Java enums collection.</title><content type='html'>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho2PrjGPBmwSBoW58NPfHQt54F2-l26lkcXfQj6EOnnblzGWcklftKBA2f4Et2Ygb-3ivCgHqJ1j9tzlosKTVFrr-_6Tw-YLvLEg4vGc_fqgY6zXsZEVT1y6N0JQRiqrNMRrcXN1BnPDo/s1600-h/many_to_one.png&quot; class=&quot;snap_noshots&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho2PrjGPBmwSBoW58NPfHQt54F2-l26lkcXfQj6EOnnblzGWcklftKBA2f4Et2Ygb-3ivCgHqJ1j9tzlosKTVFrr-_6Tw-YLvLEg4vGc_fqgY6zXsZEVT1y6N0JQRiqrNMRrcXN1BnPDo/s320/many_to_one.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5192038990640806226&quot; border=&quot;0&quot; /&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=&quot;java&quot; name=&quot;code&quot;&gt;
@Enumerated(EnumType.STRING)
@Column(name=&quot;color&quot;)
private ColorEnum color = ColorEnum.RED;
&lt;/pre&gt;
to
&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;
@CollectionOfElements
@JoinTable( name=&quot;item_colors&quot;,joinColumns={@JoinColumn(name=&quot;item_id&quot;)}           )
@Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@Enumerated(value=EnumType.STRING)
@Column( name=&quot;color&quot;, 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=&quot;sql&quot; name=&quot;code&quot;&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;</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/fullpage/post/3086643476690485109/4307199441874789099' title='3 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/4307199441874789099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/4307199441874789099'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2008/04/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho2PrjGPBmwSBoW58NPfHQt54F2-l26lkcXfQj6EOnnblzGWcklftKBA2f4Et2Ygb-3ivCgHqJ1j9tzlosKTVFrr-_6Tw-YLvLEg4vGc_fqgY6zXsZEVT1y6N0JQRiqrNMRrcXN1BnPDo/s72-c/many_to_one.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="framework"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="jaxb"/><category scheme="http://www.blogger.com/atom/ns#" term="xml"/><title type='text'>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&#39;annoter vos classes. 
Voici un exemple simple d&#39;une classe &#39;Product&#39; annotée avec jaxb :
&lt;pre name=&quot;code&quot; class=&quot;java&quot;&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 &#39;Product&#39; est la suivante :
&lt;pre name=&quot;code&quot; class=&quot;xml&quot;&gt;
&amp;lt;product name=&quot;foo&quot; id=&quot;123&quot;/&amp;gt;
&lt;/pre&gt;

Le code Java pour produire ce XML est aussi très simple :
&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;
// Create a product
Product product = new Product();
product.setId(123);
product.setName(&quot;foo&quot;);

// Get the jaxb context.
JAXBContext context = JAXBContext.newInstance(ProductList.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, &quot;UTF-8&quot;);
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&#39;héritage&lt;/h3&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs3NNZJclKKciB198bIreJtVJzyDzhWbKY4tY5A3TdXAdZQ4p3L7vFRcZVodaLyKDS4q5IfR7ADlYztDk6iQYeaeIAOfjv0WE6jRscNzwPksa5Mfv7Uqyfy_zSVL9WtK1EJUgVG0TrHGs/s1600-h/jaxb_inheritance_customization.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs3NNZJclKKciB198bIreJtVJzyDzhWbKY4tY5A3TdXAdZQ4p3L7vFRcZVodaLyKDS4q5IfR7ADlYztDk6iQYeaeIAOfjv0WE6jRscNzwPksa5Mfv7Uqyfy_zSVL9WtK1EJUgVG0TrHGs/s400/jaxb_inheritance_customization.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5167697838138696978&quot; border=&quot;0&quot;&gt;&lt;/a&gt;
Jouons maintenant un peu avec l&#39;héritage pour voir comment se comporte jaxb. Voici deux nouvelles classes qui héritent de produit.
&lt;pre name=&quot;code&quot; class=&quot;java&quot;&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=&quot;code&quot; class=&quot;java&quot;&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=&quot;code&quot; class=&quot;java&quot;&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=&quot;code&quot; class=&quot;java&quot;&gt;
// Create 2 products
MovieProduct inTheMoonForLove =  new MovieProduct();
inTheMoonForLove.setId(1L);
inTheMoonForLove.setName(&quot;In the moon for love&quot;);

WallpaperProduct tuxLogo = new WallpaperProduct();
tuxLogo.setId(2L);
tuxLogo.setName(&quot;Tux !&quot;);
tuxLogo.setWidth(128);
tuxLogo.setHeight(128);

// Create a new product list
ProductList productList = new ProductList();
productList.setName(&quot;My favorite product list&quot;);
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, &quot;UTF-8&quot;);
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=&quot;My favorite product list&quot;&amp;gt;
&amp;lt;product name=&quot;Tux !&quot; id=&quot;2&quot;/&amp;gt;
&amp;lt;product name=&quot;In the moon for love&quot; id=&quot;1&quot;/&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=&quot;code&quot; class=&quot;java&quot;&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=&quot;code&quot; class=&quot;xml&quot;&gt;
&amp;lt;productlist name=&quot;My favorite product list&quot;&amp;gt;
&amp;lt;wallpaperproduct height=&quot;128&quot; width=&quot;128&quot; name=&quot;Tux !&quot; id=&quot;2&quot;/&amp;gt;
&amp;lt;movieproduct name=&quot;In the moon for love&quot; id=&quot;1&quot;/&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</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/fullpage/post/3086643476690485109/5368224990686936607' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/5368224990686936607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/5368224990686936607'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2008/02/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs3NNZJclKKciB198bIreJtVJzyDzhWbKY4tY5A3TdXAdZQ4p3L7vFRcZVodaLyKDS4q5IfR7ADlYztDk6iQYeaeIAOfjv0WE6jRscNzwPksa5Mfv7Uqyfy_zSVL9WtK1EJUgVG0TrHGs/s72-c/jaxb_inheritance_customization.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="connector"/><category scheme="http://www.blogger.com/atom/ns#" term="mod_jk"/><category scheme="http://www.blogger.com/atom/ns#" term="tomcat"/><category scheme="http://www.blogger.com/atom/ns#" term="vhost"/><title type='text'>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&#39;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 &quot;[%a %b %d %H:%M:%S %Y] &quot;
   # 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 &#39;All&#39; in the main server.

&lt;pre&gt;
JkMountCopy All
&lt;/pre&gt;

see http://tomcat.apache.org/connectors-doc/reference/apache.html</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/fullpage/post/3086643476690485109/6911459419951734671' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/6911459419951734671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/6911459419951734671'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2008/02/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="hibernate"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>Hibernate read only query</title><content type='html'>Here an example of a read only Hibernate query :
&lt;pre class=&quot;java&quot; name=&quot;code&quot;&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(
     &quot;select p from Product&quot;).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;</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/fullpage/post/3086643476690485109/8686438037449081226' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/8686438037449081226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/8686438037449081226'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2008/01/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="database"/><category scheme="http://www.blogger.com/atom/ns#" term="php"/><title type='text'>PHP + innodb + utf8</title><content type='html'>Il m&#39;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&#39;est simple, puissant mais bordelique ! C&#39;est un peu comme un pouding, ça donne envie, et c&#39;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&#39;ai terminé le script en 30 minutes mais suprise le fichier xml produit contenait des caratères non utf8 ?!  J&#39;ai passé 20 minutes à tester différentes solutions d&#39;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=&quot;code&quot; class=&quot;ruby&quot;&gt;
//Force default client encoding
mysql_query(&quot;SET NAMES utf8&quot;);
&lt;/pre&gt;

Beaucoup de personnes m&#39;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 (&#39;éàûôâç&#39;);
&lt;/pre&gt;


Et un script php pour tester le client :
&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;

$link = mysql_connect(&quot;127.0.0.1&quot;, &quot;root&quot;, &quot;&quot;)
   or die(&quot;Impossible de se connecter : &quot; . mysql_error());

if (!mysql_select_db(&#39;test&#39;, $link)) {
   echo &#39;Sélection de base de données impossible&#39;;
   exit;
}

//Force default client encoding
//mysql_query(&quot;SET NAMES utf8&quot;);

$sql    = &#39;SELECT * FROM test_encoding&#39;;
$result = mysql_query($sql, $link);

if (!$result) {
   echo &quot;Erreur DB, impossible d&#39;effectuer une requête\n&quot;;
   echo &#39;Erreur MySQL : &#39; . mysql_error();
   exit;
}

while ($row = mysql_fetch_assoc($result)) {
   echo $row[&#39;name&#39;].&quot;\n&quot;;
}

mysql_free_result($result);

mysql_close($link);

&lt;/pre&gt;

Quand on ne force pas l&#39;encoding du client, php semble récupérer les données utf8 du serveur en latin1. J&#39;adore les pb d&#39;encoding :-)</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/fullpage/post/3086643476690485109/3003009747096941040' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/3003009747096941040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/3003009747096941040'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2008/01/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="hibernate"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>Hibernate + IndexColumn</title><content type='html'>Hier, un ami m&#39;a contacté pour me parler d&#39;un problème de mapping avec Hibernate.
Il essayait de créer une entité &lt;span style=&quot;font-weight: bold;&quot;&gt;Node&lt;/span&gt; avec une propriété &lt;span style=&quot;font-style: italic;&quot;&gt;parent&lt;/span&gt; et une collection indexée &lt;span style=&quot;font-style: italic;&quot;&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=&quot;code&quot; class=&quot;java&quot;&gt;
@Entity
@Table(name=&quot;node&quot;)
public class Node {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@OneToMany(mappedBy=&quot;parent&quot;, cascade=CascadeType.ALL)
@org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@org.hibernate.annotations.IndexColumn(name=&quot;child_position&quot;)
private List&lt;node&gt; children = new ArrayList&lt;node&gt;();

@ManyToOne
@JoinColumn(name=&quot;parent_id&quot;)
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&#39;erreur suivante : &lt;span style=&quot;font-style: italic;&quot;&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=&quot;font-style: italic;&quot;&gt;children&lt;/span&gt; n&#39;est pas mise à jour quand un noeud enfant est ajouté au noeud principal. C&#39;est normal puisque la relation OneToMany à l&#39;attribut mappedBy = &quot;parent&quot; qui est équivalent à &quot;inverse=true&quot; dans un fichier hbm.xml : c&#39;est donc le coté &lt;span style=&quot;font-style: italic;&quot;&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=&quot;code&quot; class=&quot;java&quot;&gt;
@Entity
@Table(name = &quot;nodes&quot;)
public class Node implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Integer Id;

  private String name;

  @ManyToOne
  @JoinColumn(name = &quot;parent_id&quot;, insertable=false, updatable=false)
  private Node parent;

  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name = &quot;parent_id&quot;)
  @org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
  @org.hibernate.annotations.IndexColumn(name = &quot;child_position&quot;)
  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&#39;attribut &quot;mappedBy&quot; a été supprimé et les attributs &quot;insertable=false&quot; et &quot;updatable=false&quot; ont été ajoutés à l&#39;annotation @JoinColumn du coté ManyToOne. C&#39;est donc le côté OneToMany qui est responsable de la relation bi-directionnelle ( parent &lt;-&gt; enfants). Cette manipulation revient à mettre l&#39;attribut &quot;inverse=false&quot; dans un ficher hbm.xml sur le côté ManyToOne.
&lt;/p&gt;
&lt;p&gt;
Hibernate c&#39;est pas toujours simple :-) Je me demande comment on fait ce type de mapping avec Rails et Active Records.&lt;/p&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/fullpage/post/3086643476690485109/9145035783438131358' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/9145035783438131358'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/9145035783438131358'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2007/12/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><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><title type='text'>Hibernate Search and Null value</title><content type='html'>&lt;p&gt;
&lt;a href=&quot;http://www.hibernate.org/&quot;&gt;Hibernate Search&lt;/a&gt; permet d&#39;indexer les propriétés et les relations de vos POJO dans un index Lucene pour faire des recherches à la Google. J&#39;ai récemment utilisé Hibernate Search pour indexer des tags et leurs traductions. Dans mon modèle l&#39;objet traduction avec la propriété language == &#39;null&#39; est la traduction par defaut du tag. Problème ! &lt;a href=&quot;http://lucene.apache.org/&quot;&gt;Lucene&lt;/a&gt; ne peut pas indexer un objet null.&lt;br/&gt; La solution est d&#39;é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=&quot;font-style: italic;&quot;&gt;null&lt;/span&gt;.
&lt;/p&gt;
&lt;p&gt;
J&#39;ai alors proposé une &lt;a href=&quot;http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-115?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel&quot;&gt;amélioration&lt;/a&gt;  au committers d&#39;Hibernate Search: spécifier une valeur par défault dans l&#39;annotation @Field pour les valeurs &lt;span style=&quot;font-style: italic;&quot;&gt;null&lt;/span&gt;.
&lt;/p&gt;
&lt;br/&gt;
Voici mon POJO TagTranslation annoté avec Hibernate Search:
&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;
@Entity()
@Table(name=&quot;indexing_tag_trans&quot;)
@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=&quot;translation_id&quot;)
  @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=&quot;code&quot; class=&quot;java&quot;&gt;
  @Field(index=Index.UN_TOKENIZED, store=Store.NO, nullValue=&quot;DEFAULT&quot;)
  private String language;
&lt;/pre&gt;


La bonne nouvelle vient de tomber ce matin dans ma mail box :
&lt;pre style=&quot;overflow:scroll&quot;&gt;
Emmanuel Bernard updated HSEARCH-115:
-------------------------------------

   Fix Version/s: 3.1.0
                  3.0.1

I don&#39;t know the impact, but we should at least introduce that to 3.1.0
&lt;/pre&gt;
&lt;p style=&quot;text-align:center&quot;&gt;
&lt;b&gt;COOOOOOOOOOOOL !&lt;/b&gt;
&lt;/p&gt;
&lt;span&gt;
Déjà qu&#39;Emmanuel Bernard n&#39;avait répondu en moins d&#39;une heure pour me fournir un workaround (le custom fieldbridge) ! Bravo, Emmanuel et aussi à toute l&#39;équipe d&#39;Hibernate pour votre réactivité et la qualité de votre travail !
&lt;/span&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/fullpage/post/3086643476690485109/6978751583691836366' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/6978751583691836366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/6978751583691836366'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2007/10/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><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><category scheme="http://www.blogger.com/atom/ns#" term="hibernate"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="struts"/><category scheme="http://www.blogger.com/atom/ns#" term="validator"/><title type='text'>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&#39;est le cas de beaucoup d&#39;applications web Java sous Struts v1.x : la validation des données soumises par l&#39;utilisateur  passe par la methode validate d&#39;un objet ActionForm ou directement dans l&#39;action. Une alternative est d&#39;utiliser &lt;a href=&quot;http://www.hibernate.org/412.html&quot;&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&#39;un formulaire avec &lt;a href=&quot;http://www.hibernate.org/412.html&quot;&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&#39;abord vous devez annoter les propriétés de vos entités avec les annotations &lt;a href=&quot;http://www.hibernate.org/412.html&quot;&gt;Hibernate Validator&lt;/a&gt;. Voici un exemple d&#39;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&#39;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=&quot;code&quot; class=&quot;java:nogutter&quot;&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=&quot;.*\\.(gif|jpg|png)$&quot;, flags=java.util.regex.Pattern.CASE_INSENSITIVE)
private String imageURL;

@Digits(integerDigits=10, fractionalDigits=2)
private Double price;

@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name=&quot;categorized_product&quot;)
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&#39;utilise la méthode validate d&#39;un ActionForm pour valider les données du formulaire. Je vous passe les details de la configuration Struts, c&#39;est pas le sujet. Voici le code de la méthode validate de ma classe ProductForm.
&lt;/span&gt;
&lt;pre name=&quot;code&quot; class=&quot;java:nogutter&quot;&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(&quot;errors.detail&quot;, error.getPropertyName() + &quot;: &quot; +error.getMessage()));
        }

    } catch (Exception e){
        errors.add(ActionMessages.GLOBAL_MESSAGE,
                    new ActionMessage(&quot;errors.general&quot;));
        errors.add(ActionMessages.GLOBAL_MESSAGE,
                    new ActionMessage(&quot;errors.detail&quot;,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&#39;action). La méthode validate crée un objet du modèle (Product) et le peuple avec les données de l&#39;ActionForm. Ensuite on crée un objet ClassValidator en passant au constructeur le type de l&#39;objet qui doit être validé. Enfin on appelle la méthode getInvalidValues pour récupérer un tableau d&#39;objets InvalidValue contenant le nom de la propriété et le message d&#39;erreur (vous pouvez comme dans struts personnaliser les messages d&#39;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=&quot;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%;&quot;&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=&quot;/AddProduct&quot; &amp;gt;
    &amp;lt;label&amp;gt;Title:&amp;lt;/label&amp;gt;
    &amp;lt;html:text property=&quot;title&quot; /&amp;gt;
    &amp;lt;br/&amp;gt;
    &amp;lt;label&amp;gt;Description:&amp;lt;/label&amp;gt;
    &amp;lt;html:textarea property=&quot;description&quot; /&amp;gt;
     &amp;lt;br/&amp;gt;
    &amp;lt;label&amp;gt;Image URL:&amp;lt;/label&amp;gt;
    &amp;lt;html:text property=&quot;imageURL&quot;/&amp;gt;
     &amp;lt;br/&amp;gt;
    &amp;lt;label&amp;gt;Price:&amp;lt;/label&amp;gt;
    &amp;lt;html:text property=&quot;price&quot;/&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&#39;utilisateur pour correction comme ci-dessous.
&lt;/span&gt;
&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvW1qtIDIzX6DXVT9akijGzKu_VhdfL_Op_qMkMKJ1Z8HbUiOGLRDMObj7KL7EmiRRSZwOsSoEhMpgbXKm40LalSgTWTF-IZjxo3aAmqPKZHNOR1Kfi4-nHi0xyL9udxJZNWs_FKRBXvE/s1600-h/Image+2.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvW1qtIDIzX6DXVT9akijGzKu_VhdfL_Op_qMkMKJ1Z8HbUiOGLRDMObj7KL7EmiRRSZwOsSoEhMpgbXKm40LalSgTWTF-IZjxo3aAmqPKZHNOR1Kfi4-nHi0xyL9udxJZNWs_FKRBXvE/s320/Image+2.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5110548952582971954&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;

&lt;span&gt;
Vous pouvez télécharger le code et le projet Netbeans &lt;a href=&quot;http://jbrulin.free.fr/juliusdev/hibernate-validator-struts.zip&quot;&gt;ici&lt;/a&gt;.
&lt;/span&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/fullpage/post/3086643476690485109/4265129328255738028' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/4265129328255738028'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/4265129328255738028'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2007/09/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvW1qtIDIzX6DXVT9akijGzKu_VhdfL_Op_qMkMKJ1Z8HbUiOGLRDMObj7KL7EmiRRSZwOsSoEhMpgbXKm40LalSgTWTF-IZjxo3aAmqPKZHNOR1Kfi4-nHi0xyL9udxJZNWs_FKRBXvE/s72-c/Image+2.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><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><title type='text'>Cellfish is Mobile 2.0 ?</title><content type='html'>Je travaille depuis 6 ans chez &lt;a href=&quot;http://www.cellfishmedia.fr&quot;&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=&quot;http://www.cellfish.com&quot;&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=&quot;420&quot; height=&quot;315&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://cellfish.com/static/swf/player8.swf?Id=155282&quot; /&gt;&lt;param name=&quot;wmode&quot; value=&quot;window&quot; /&gt;&lt;embed src=&quot;http://cellfish.com/static/swf/player8.swf?Id=155282&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;window&quot; width=&quot;420&quot; height=&quot;315&quot; &gt;&lt;/embed&gt;&lt;/object&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/fullpage/post/3086643476690485109/7314734889886519023' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/7314734889886519023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/7314734889886519023'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2007/08/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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3086643476690485109.post-5984767779263673045</id><published>2007-07-24T00:20:00.000+02:00</published><updated>2007-08-24T14:27:13.587+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="mysql"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>JRuby and Mysql (jdbc)</title><content type='html'>Bonjour,

Je suis en train de tester la M10 de Netbeans avec le support de Ruby (JRuby). Le but de mon test est d&#39;utiliser l&#39;efficacité de la syntaxe du langage de script Ruby pour manipuler de données en base (mysql) avec Netbeans comme IDE. C&#39;est quand même pratique d&#39;utiliser Ruby ou un autre DSL que Java pour faire des imports ou des exports de données :-) . Après avoir lu quelques tutorials sur le net, voici le bout de code ruby stupide que j&#39;ai réussi à pondre :
&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;
# main.rb
# 23 juillet 2007
#

require &#39;mysql&#39;

con = Mysql.new(&#39;localhost&#39;,&#39;root&#39;,&#39;&#39;,&#39;test&#39;)
rs = con.query(&quot;select * from flex_product&quot;)
rs.each_hash{ |h| puts h[&#39;pname&#39;]}
con.close

&lt;/pre&gt;

Ce code fonctionne avec la version native de Ruby sous OSX  (le &lt;a href=&quot;http://www.juretta.com/log/2006/10/13/ruby_installing_ruby_mysql_driver_on_intel_macs/&quot;&gt;module &lt;span style=&quot;font-style: italic;&quot;&gt;mysql&lt;/span&gt; doit être installé ) &lt;/a&gt; mais pas sous Netbeans ! Et oui le module &lt;span style=&quot;font-style: italic;&quot;&gt;mysql&lt;/span&gt; n&#39;est pas dans la gems liste de Netbeans, il n&#39;y a qu&#39;un wrapper active_records pour jdbc (c&#39;est super pour utiliser RoR mais ça sert rien dans mon cas). Alors après quelques recherche sur le net j&#39;ai trouvé des articles comme &lt;a href=&quot;http://rubylearning.com/blog/2007/05/05/connect-jruby-to-mysql-using-jdbc/&quot;&gt;celui ci&lt;/a&gt; qui expliquent comment utiliser JDBC avec JRuby. Et voici le code version JDBC :
&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;
# mysql_jdbc.rb
# 24 juillet 2007
#

require &#39;java&#39;

module JavaLang
include_package &quot;java.lang&quot;
end

module JavaSql
include_package &#39;java.sql&#39;
end

begin
JavaLang::Class.forName(&quot;com.mysql.jdbc.Driver&quot;).newInstance
conn = JavaSql::DriverManager.getConnection(&quot;jdbc:mysql://localhost:3306/test?user=root&quot;);
stmt = conn.createStatement
rs = stmt.executeQuery(&quot;select * from flex_product&quot;)
while (rs.next) do
puts rs.getString(&quot;pname&quot;)
end
rs.close
stmt.close
conn.close()
rescue JavaLang::ClassNotFoundException
puts &quot;ClassNotFoundException&quot;
rescue JavaSql::SQLException
puts &quot;SQLException&quot;
end
&lt;/pre&gt;
Bon on est tous d&#39;accord c&#39;est moins sexy que la version native :-) Mais bon ça marche, faut juste que quelques bons développeurs se lancent dans un projet de wrapper JDBC pour Ruby et on aura une interface un peu plus adapter à la syntaxe de Ruby.</content><link rel='replies' type='application/atom+xml' href='http://juliusdev.blogspot.com/feeds/5984767779263673045/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3086643476690485109/5984767779263673045' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/5984767779263673045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/5984767779263673045'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2007/07/jruby-and-mysql-jdbc.html' title='JRuby and Mysql (jdbc)'/><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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3086643476690485109.post-5580225790741170380</id><published>2007-07-19T23:51:00.000+02:00</published><updated>2007-07-19T23:59:38.037+02:00</updated><title type='text'>TéléTravail</title><content type='html'>Après 7 ans à Paris, me voici de retour dans le Var :-)

Je ne comprends toujours pas &lt;span class=&quot;blsp-spelling-corrected&quot; id=&quot;SPELLING_ERROR_0&quot;&gt;pourquoi&lt;/span&gt; Google ne veut pas venir s&#39;installer à coté de chez moi, il fait chaud, la plage n&#39;est pas &lt;span class=&quot;blsp-spelling-corrected&quot; id=&quot;SPELLING_ERROR_1&quot;&gt;loins&lt;/span&gt;, bon &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_2&quot;&gt;ok&lt;/span&gt; il manque quand même quelque chose : un &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_3&quot;&gt;starbuck&lt;/span&gt; café ...

Bon allez sans blague, il n&#39;y a pas que la télé dans le &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_4&quot;&gt;télé-travail&lt;/span&gt; alors au boulot ! J&#39;espère publier un article sur &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_5&quot;&gt;Flex&lt;/span&gt; et &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_6&quot;&gt;Hibernate&lt;/span&gt; sur ce blog cette semaine.</content><link rel='replies' type='application/atom+xml' href='http://juliusdev.blogspot.com/feeds/5580225790741170380/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3086643476690485109/5580225790741170380' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/5580225790741170380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3086643476690485109/posts/default/5580225790741170380'/><link rel='alternate' type='text/html' href='http://juliusdev.blogspot.com/2007/07/tltravail.html' title='TéléTravail'/><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='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>