<?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;C0UDRXk7fCp7ImA9WhRRFEk.&quot;"><id>tag:blogger.com,1999:blog-8557381644441801065</id><updated>2011-11-28T01:47:54.704+01:00</updated><title>grooveek.metaClass.blog = {shareDiscoveries()}</title><subtitle type="html">Ideas about Groovy and Java. Some Grails stuff and plenty of other things</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://grooveek.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://grooveek.blogspot.com/" /><author><name>grooveek</name><uri>http://www.blogger.com/profile/02670644989809112570</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="33" height="29" src="http://4.bp.blogspot.com/_kB38xVro854/SqeVlFWKYwI/AAAAAAAAAAM/jUcGh4N8L3o/S220/photo_fb.png" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>4</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/grooveek" /><feedburner:info uri="grooveek" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;C0YMRHgzfip7ImA9WxNRGUo.&quot;"><id>tag:blogger.com,1999:blog-8557381644441801065.post-4934725685087218492</id><published>2009-09-15T01:22:00.004+02:00</published><updated>2009-09-15T01:33:05.686+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-15T01:33:05.686+02:00</app:edited><title>Playing again with zip and Groovy MOP ( and spread operator)</title><content type="html">After I posted the &lt;a href="http://grooveek.blogspot.com/2009/09/adding-zipping-and-unzipping.html"&gt;zip and unzip snippet&lt;/a&gt;, I came accross an interesting question on &lt;a href="http://www.gr8forums.org"&gt;gr8forums.org&lt;/a&gt;.&lt;br /&gt;
Someone told me it would be great if ths code could be applied to an array of files.&lt;br /&gt;
&lt;br /&gt;
That's a good use case, isn't it ? So, I thought about it and saw immediately which groovy 'magic item' could be useful : the spread operator aka star-dot operator, mister &lt;b&gt;*.&lt;/b&gt; &lt;br /&gt;
Better than I could explain myself, here's what's said about this little thing in Groovy's doc :&lt;br /&gt;
&lt;p style="background:CadetBlue;color:DarkBlue;padding-left:15px;"&gt;The Spread Operator is used to invoke an action on all items of an aggregate object.&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Unfortunately, ZipOutputStream in Java doesn't permit to append something to a zip file. So, I'll show you an awful (yes, unzip the existing zip-append file-rezip IS awful) implementation of this functionnality. It's just for fun, not for production, after all.&lt;br /&gt;
&lt;br /&gt;
First, you'll need a deleteDir closure, as java.io.File.delete() doesn't delete non-empty directories :&lt;br /&gt;
&lt;pre class="brush: groovy"&gt;def deleteDir
deleteDir = { File f -&gt;
    if (f?.exists()){
      f.listFiles().each{ sf -&gt;
        sf.isDirectory()?deleteDir(sf):sf.delete()
      }
    }
    f?.delete()
}
&lt;/pre&gt;&lt;br /&gt;
With this wonderful snippet, you can replace the File.metaClass.zip block in &lt;a href="http://grooveek.blogspot.com/2009/09/adding-zipping-and-unzipping.html"&gt;this snippet&lt;/a&gt; by :&lt;br /&gt;
&lt;pre class="brush: groovy"&gt;File.metaClass.zip = { String destination -&gt;
    //cache the delegate (the File Object) as it will be modified
    //in the withStream closure
    def input = delegate
    if (destination == null){
        destination = input.canonicalPath + ".zip"
    }
    def dest = new File(destination)
    def append = false
    def tmp
    if (dest.exists()){
        tmp = new File(System.properties['java.io.tmpdir'] + File.separator + 'grooz')           
        tmp.mkdir()
        dest.unzip(tmp.canonicalPath)
        append = true
    }
    def result = new ZipOutputStream(new FileOutputStream(destination))
    try{
    result.withStream {zipOutStream-&gt;
        //recursively zip files
        if (append) {
            
                tmp.eachFile{
                    zip(zipOutStream,it,"")
                }
            
        }
        zip(zipOutStream,input,"")
    }
    }
    catch(all){
      all.printStackTrace()
    }
    finally{                        
      deleteDir(tmp)
    }    
}

&lt;/pre&gt;&lt;br /&gt;
This version is very easy to use. If you want to zip a bunch of files, then list them and use the spread operator like this :&lt;br /&gt;
&lt;pre class="brush: groovy"&gt;// to zip all files in a directory
new File('/path/to/dir').listFiles()*.zip('allmyfiles.zip') 
//if you've got files instances
[file1,file2,dir1,dir2]*.zip('stuff.zip')
&lt;/pre&gt;&lt;br /&gt;
This code is not performance-friendly nor beauty-frienly and is provided as is. Every enhancement you can think of is welcome (yes, I know, it'll be difficult to improve, but you can do it ;-) )&lt;br /&gt;
&lt;br /&gt;
See you soon with a totally new subject : joy of Java Classoading !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8557381644441801065-4934725685087218492?l=grooveek.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/grooveek/~4/_C-6pcijEaY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://grooveek.blogspot.com/feeds/4934725685087218492/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://grooveek.blogspot.com/2009/09/playing-again-with-zip-and-groovy-mop.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8557381644441801065/posts/default/4934725685087218492?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8557381644441801065/posts/default/4934725685087218492?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/grooveek/~3/_C-6pcijEaY/playing-again-with-zip-and-groovy-mop.html" title="Playing again with zip and Groovy MOP ( and spread operator)" /><author><name>grooveek</name><uri>http://www.blogger.com/profile/02670644989809112570</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="33" height="29" src="http://4.bp.blogspot.com/_kB38xVro854/SqeVlFWKYwI/AAAAAAAAAAM/jUcGh4N8L3o/S220/photo_fb.png" /></author><thr:total>1</thr:total><feedburner:origLink>http://grooveek.blogspot.com/2009/09/playing-again-with-zip-and-groovy-mop.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0IHQHcyeSp7ImA9WxNRGUo.&quot;"><id>tag:blogger.com,1999:blog-8557381644441801065.post-6509924833942654110</id><published>2009-09-11T01:00:00.003+02:00</published><updated>2009-09-15T01:38:51.991+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-15T01:38:51.991+02:00</app:edited><title>Adding Zipping and unzipping capabilities to Java.io.File via Groovy MOP</title><content type="html">&lt;p style="background:CadetBlue;color:DarkBlue;padding-left:15px;"&gt;this post has an update : &lt;a href="http://grooveek.blogspot.com/2009/09/playing-again-with-zip-and-groovy-mop.html"&gt;Playing again with zip and Groovy MOP ( and spread operator)&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
[First technical post, and I don't know how to begin... Please be kind with me]&lt;br /&gt;
So, as I'm writing a Plugin System in Groovy, I needed to zip and unzip so-called 'Bundles' which contain config files, Plugin jars and dependencies.&lt;br /&gt;
&lt;br /&gt;
I didn't want to make a classical FileUtils or BundleUtils class, and I decided to try Groovy MOP (Meta Object Protocol) to directly modify the java.io.File so I could write &lt;br /&gt;
&lt;pre class="brush: groovy"&gt;new File('/path/to.file').zip(/path/to.zip)&lt;/pre&gt;&lt;br /&gt;
First thing to do is adding capability when you need to. As an example, I decided to load the capability statically in a Class. You could either have a bootsrap class that loads your metaprogramming functionnalities before starting your App. This is your choice&lt;br /&gt;
&lt;pre class="brush: groovy"&gt;static{
  bootstrapPluginSystem()
}

private static void bootstrapPluginSystem(){
   //zipping methods here
   ..................
   //unzipping methods here
   ..................
}
&lt;/pre&gt;&lt;br /&gt;
Zipping files is easy in Java and is performed via the &lt;a href="http://www.j2ee.me/javase/6/docs/api/java/util/zip/ZipOutputStream.html"&gt;ZipOutputStream&lt;/a&gt; class.&lt;br /&gt;
&lt;br /&gt;
One of the grooviest groovy goodies is the ability to work seamlessly with streams without boilerplate resource closing code&lt;br /&gt;
Simply use the &lt;a href="http://groovy.codehaus.org/groovy-jdk/java/io/InputStream.html#withStream"&gt;withStream&lt;/a&gt; method, and Groovy manage the resource for you. How great it is !!!&lt;br /&gt;
&lt;br /&gt;
Groovy MOP is wonderful to add methods to Class at Runtime. The simple example I take here demonstrates the power of this technique&lt;br /&gt;
&lt;br /&gt;
Zipping is quite easy :&lt;br /&gt;
&lt;pre class="brush: groovy"&gt;//define zip closure first, then allocate it
 //it is needed to make the recursion work
 def zip
 zip = { ZipOutputStream zipOutStream,File f , String path-&gt;                        
    def name = (path.equals(""))?f.name:path + File.separator + f.name
    if(!f.isDirectory() ){                            
      def entry = new ZipEntry(name)
      zipOutStream.putNextEntry(entry)
      new FileInputStream(f).withStream { inStream -&gt;
        def buffer = new byte[1024]
        def count
        while((count = inStream.read(buffer, 0, 1024)) != -1) {
          zipOutStream.write(buffer,0,count)
        }
      }
      zipOutStream.closeEntry()
    }
    else {
      //write the directory first, in order to allow empty directories
      def entry = new ZipEntry(name + File.separator)
      zipOutStream.putNextEntry(entry)
      zipOutStream.closeEntry()                            
      f.eachFile{
        //recurse
        zip(zipOutStream,it,name)
      }
    }
 }

 File.metaClass.zip = { String destination -&gt;
    //cache the delegate (the File Object) as it will be modified 
    //in the withStream closure
    def input = delegate            
    def result = new ZipOutputStream(new FileOutputStream(destination))
    result.withStream {zipOutStream-&gt;   
      //recursively zip files             
      zip(zipOutStream,input,"")
    }
 }

&lt;/pre&gt;&lt;br /&gt;
Code is almost self explaining...&lt;br /&gt;
Unzipping comes with less efforts : &lt;br /&gt;
&lt;pre class="brush: groovy"&gt;File.metaClass.unzip = { String dest -&gt;
 //in metaclass added methods, 'delegate' is the object on which 
 //the method is called. Here it's the file to unzip
 def result = new ZipInputStream(new FileInputStream(delegate))
 def destFile = new File(dest)
 if(!destFile.exists()){
   destFile.mkdir();
 }
 result.withStream{
   def entry
   while(entry = result.nextEntry){
     if (!entry.isDirectory()){
       new File(dest + File.separator + entry.name).parentFile?.mkdirs()
       def output = new FileOutputStream(dest + File.separator 
                                         + entry.name)                        
       output.withStream{
         int len = 0;
         byte[] buffer = new byte[4096]
         while ((len = result.read(buffer)) &gt; 0){
           output.write(buffer, 0, len);
         }
       }
    }
    else {
      new File(dest + File.separator + entry.name).mkdir()
    }
   }
 }
}

&lt;/pre&gt;&lt;br /&gt;
All that is not really thoroughly tested, but I managed to zip and unzip the grails project directory without problems. I can also unzip with Ark files zipped by these lines of code&lt;br /&gt;
&lt;br /&gt;
Here are minimal tests :&lt;br /&gt;
&lt;pre class="brush: groovy"&gt;import groovy.util.GroovyTestCase
/**
 *
 * @author grooveek
 */
class ZipTest extends GroovyTestCase{
 // load the static block to add zip capabilities
 static def bootstrap = new BootStrap()

 void testZipUnzip(){
   def fi = new File('testfiles')
   if (!fi.exists()){
     fi.mkdir()
   }
   def writer = new File('testfiles/ziptest.txt').newWriter()
   100.times{
     writer.writeLine("$it")
   }
   writer.close()
   //testing zipping/unzipping
   def fileToZip = new File('testfiles/ziptest.txt')
   fileToZip.zip('testfiles/toto.zip')
   def zipToUnzip = new File('testfiles/toto.zip')
   zipToUnzip.unzip('testfiles/ziptestdir')
 }

 void testZipUnzipWithDirectories(){
   def fi = new File('testfiles')
   if (!fi.exists()){
     fi.mkdir()
   }
   new File('testfiles/toto/titi').mkdirs()
   def writer = new File('testfiles/toto/titi/ziptest.txt').newWriter()
   100.times{
     writer.writeLine("$it")
   }
   writer.close()
   //testing zipping/unzipping
   def fileToZip = new File('testfiles/toto')
   fileToZip.zip('testfiles/toto2.zip')
   def zipToUnzip = new File('testfiles/toto2.zip')
   zipToUnzip.unzip('testfiles/ziptestdir2')
 }

 void testZipUnzipWithDirectoriesAndMultipleFiles(){
   def fi = new File('testfiles')
   if (!fi.exists()){
     fi.mkdir()
   }
   new File('testfiles/tata/titi').mkdirs()
   5.times{
     def writer = new File("testfiles/tata/titi/ziptest${it}.txt").newWriter()
     100.times{
       writer.writeLine("$it")
     }
     writer.close()
   }
   new File('testfiles/tata/titi/toto').mkdirs()
   5.times{
     def writer = new File("testfiles/tata/titi/toto/ziptest${it}.txt").newWriter()
     100.times{
       writer.writeLine("$it")
     }
     writer.close()
   }
   new File('testfiles/tata/titi/toto/tutu').mkdirs()
   //testing zipping/unzipping
   def fileToZip = new File('testfiles/tata')
   fileToZip.zip('testfiles/toto3.zip')
   def zipToUnzip = new File('testfiles/toto3.zip')
   zipToUnzip.unzip('testfiles/ziptestdir3')
}
        

 void testZipBigAndDeepDirectory(){
   def fileToZip = new File("/home/grooveek/grails-1.1.1")
   fileToZip.zip("testfiles/grails.zip")
   def zipToUnzip = new File('testfiles/grails.zip')
   zipToUnzip.unzip('testfiles')
 }
}
&lt;/pre&gt;&lt;br /&gt;
I hope you enjoyed reading&lt;br /&gt;
Don't forget to let a kind word (or something not so kind if that's your mind)you want&lt;br /&gt;
&lt;br /&gt;
See you soon&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.twitter.com/grooveek"&gt;@grooveek&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8557381644441801065-6509924833942654110?l=grooveek.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/grooveek/~4/XkowCJIjYwg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://grooveek.blogspot.com/feeds/6509924833942654110/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://grooveek.blogspot.com/2009/09/adding-zipping-and-unzipping.html#comment-form" title="7 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8557381644441801065/posts/default/6509924833942654110?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8557381644441801065/posts/default/6509924833942654110?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/grooveek/~3/XkowCJIjYwg/adding-zipping-and-unzipping.html" title="Adding Zipping and unzipping capabilities to Java.io.File via Groovy MOP" /><author><name>grooveek</name><uri>http://www.blogger.com/profile/02670644989809112570</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="33" height="29" src="http://4.bp.blogspot.com/_kB38xVro854/SqeVlFWKYwI/AAAAAAAAAAM/jUcGh4N8L3o/S220/photo_fb.png" /></author><thr:total>7</thr:total><feedburner:origLink>http://grooveek.blogspot.com/2009/09/adding-zipping-and-unzipping.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMER387eCp7ImA9WxNREko.&quot;"><id>tag:blogger.com,1999:blog-8557381644441801065.post-1406409705556075635</id><published>2009-09-06T23:52:00.001+02:00</published><updated>2009-09-07T00:00:06.100+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-07T00:00:06.100+02:00</app:edited><title>What strikes me in Groovy ...</title><content type="html">&lt;pre class="brush: groovy" name="code"&gt;// Simple list with names.
def names = ['groovy', 'grails', 'mrhaki']

// Simple closure.
names.each { println 'Normal closure says: Hello ' + it + '!' }

// Groovy method to convert to closure.
def groovySays(s) {
 "Groovy says: Hello ${s}!"
}
// Use .&amp;amp; syntax to convert method to closure.
names.each(this.&amp;amp;groovySays)

// Convert Java method to closure and use it.
def javaSays = JavaObject.&amp;amp;javaSays
names.each javaSays

&lt;/pre&gt;&lt;br /&gt;
This code comes from &lt;a href="http://mrhaki.blogspot.com/2009/08/groovy-goodness-turn-methods-into.html"&gt;mr haki's blog&lt;/a&gt;. What I like here is the ability to switch from Java to Groovy ! You can have the power of Java with the simplicity of Groovy&lt;br /&gt;
(and that's also a test post for the &lt;a href="http://alexgorbatchev.com/wiki/SyntaxHighlighter"&gt;syntax highlighting plugin&lt;/a&gt;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8557381644441801065-1406409705556075635?l=grooveek.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/grooveek/~4/mw40tSVaqSM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://grooveek.blogspot.com/feeds/1406409705556075635/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://grooveek.blogspot.com/2009/09/what-strikes-me-in-groovy.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8557381644441801065/posts/default/1406409705556075635?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8557381644441801065/posts/default/1406409705556075635?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/grooveek/~3/mw40tSVaqSM/what-strikes-me-in-groovy.html" title="What strikes me in Groovy ..." /><author><name>grooveek</name><uri>http://www.blogger.com/profile/02670644989809112570</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="33" height="29" src="http://4.bp.blogspot.com/_kB38xVro854/SqeVlFWKYwI/AAAAAAAAAAM/jUcGh4N8L3o/S220/photo_fb.png" /></author><thr:total>0</thr:total><feedburner:origLink>http://grooveek.blogspot.com/2009/09/what-strikes-me-in-groovy.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUENQnkyfip7ImA9WxNREkk.&quot;"><id>tag:blogger.com,1999:blog-8557381644441801065.post-1795175434214493491</id><published>2009-09-06T15:28:00.000+02:00</published><updated>2009-09-06T15:28:13.796+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-06T15:28:13.796+02:00</app:edited><title>Welcome to this blog</title><content type="html">I love Groovy and Java. I mean : I LOVE Groovy and Java. I'm writing here to share experiences, and to get some help sometimes as I'm not a Groovy Champion ;-)&lt;br /&gt;
Feel free to share your feelings about Groovy and Java technologies here and please, please.... excuse me for my bad english. I'm French and would be really happy to find people who want to talk about what's really fun in coding !&lt;br /&gt;
&lt;br /&gt;
My best JVM-related technologies at this time (just) :&lt;br /&gt;
* Groovy / Grails /Gorm&lt;br /&gt;
* Spring&lt;br /&gt;
* Gridgain&lt;br /&gt;
* HtmlUnit / Webtest&lt;br /&gt;
&lt;br /&gt;
Enjoy your readings&lt;br /&gt;
&lt;br /&gt;
Grooveek&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8557381644441801065-1795175434214493491?l=grooveek.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/grooveek/~4/WXMN_6AslAk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://grooveek.blogspot.com/feeds/1795175434214493491/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://grooveek.blogspot.com/2009/09/welcome-to-this-blog.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8557381644441801065/posts/default/1795175434214493491?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8557381644441801065/posts/default/1795175434214493491?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/grooveek/~3/WXMN_6AslAk/welcome-to-this-blog.html" title="Welcome to this blog" /><author><name>grooveek</name><uri>http://www.blogger.com/profile/02670644989809112570</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="33" height="29" src="http://4.bp.blogspot.com/_kB38xVro854/SqeVlFWKYwI/AAAAAAAAAAM/jUcGh4N8L3o/S220/photo_fb.png" /></author><thr:total>0</thr:total><feedburner:origLink>http://grooveek.blogspot.com/2009/09/welcome-to-this-blog.html</feedburner:origLink></entry></feed>

