tag:blogger.com,1999:blog-185654772024-03-12T18:48:04.701-07:00Yves Zoundi's blogMy personal blog, about Java, micro-services and some other stuff.Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.comBlogger129125tag:blogger.com,1999:blog-18565477.post-82725014206316421762019-06-18T13:21:00.001-07:002019-06-18T13:21:02.079-07:00Qubes OS first impressions<br />
Last week, I switched from <a href="https://getfedora.org/en/" target="_blank">Fedora</a> (fc27 iirc) to <a href="https://www.qubes-os.org/" target="_blank">Qubes OS</a> on my home laptop. It's an old and heavy <a href="https://www.asus.com/ROG-Republic-Of-Gamers/Laptops-Products/" target="_blank">Asus ROG laptop</a> that I typically don't use for development purposes. My current main system is an iMac pro, "almost FuLLy loaded".<br />
<br />
I'm not paranoid about privacy and security, but I think that I needed a reminder that those things are more important nowadays.<br />
- Does privacy even exist anymore on the web? Did it ever existed?<br />
- How easy is it to hack for a "script kiddie" nowadays, and what about for an "experienced hacker"? What if we replace "experienced hacker" with "organizations that have resources"?<br />
- What about the "Intel Management Engine" and its AMD equivalent? What do those things actually do? How bad is that code in <i>IME</i> or <i>PSP,</i> in terms of new vulnerabilities to expect? Hopefully such those "features" will become opt-in features for customers with options to fully disable the functionality.<br />
- What about security in our IOT devices? <u>It's always funny to log-in into your internet provider router UI and see wifi passwords displayed in plain text</u>. If your internet provider does such things, what do you think usually happen for other types of services when it comes to security or basic programming practices?<br />
- What about antivirus software? I'll never forget the early years of Kasperksy on my first PC a while back (1999-2000), it would always detect viruses, <i>that is after infection</i> and sometimes without any possible remediation... Do you believe that antivirus software can detect most viruses nowadays?<br />
<br />
<br />
So many questions, in any case let's jump to Qubes OS...<br />
<br />
<br />
<h2>
<b>System requirements</b></h2>
<br />
<h3>
<b><span style="color: blue;">RAM</span></b></h3>
I recommend at least 16 GB of RAM. On the Qubes OS website, they mention 4 GB minimum. With 4 GB and on a system that employs significantly virtualization, the experience cannot be pleasant. If this will be your main and only OS, I suggest 32 GB of RAM, if you can. I run Qubes OS on an "old" gaming laptop with 16 GB of RAM.<br />
<br />
<br />
<h3>
<b><span style="color: blue;">Storage</span></b></h3>
While an HDD will work fine, an SSD is much better. I can't really stand waiting for I/O operations on old devices. My laptop has 2 TB (HDD) while my main machine has a 4TB SSD, night and day from a performance standpoint.<br />
<br />
<h2>
<b>Ease of use</b></h2>
I do not believe that Qubes OS is good for the Linux newbie, it could be a very frustrating experience, especially if the system doesn't recognize all devices, on top of other issues.<br />
<br />
The main concepts to understand are around Qubes OS way of doing things, its tooling (clipboard, utilities, etc.) and Xen virtualization, other than that, it's just Linux (Debian and Redhat based VMs).<br />
<br />
I only spent few days on Qubes OS and my setup is far from complete.<br />
<br />
<h2>
<b>PC or laptop recommendations??</b></h2>
I do not really have anything to suggest. If you have a recent enough machine and you're able to boot the ISO image, I think that it should be possible to deal with other issues later (drivers and other problems).<br />
<br />
I think that with a Thinkpad or possibly pricy Librem laptop things should go smoothly. For new Librem laptops, I believe that Qubes OS supposedly works "out of the box".<br />
<br />
I did struggle with Broadcom wifi drivers that used to work fine with "old" Linux kernels, after 2 days I decided to just purchase a <a href="https://www.bestbuy.com/site/reviews/linksys-ac1200-dual-band-usb-3-0-adapter-black/9404119?page=5" target="_blank">Linksys USB wifi adapter</a>. I got tired of chasing old kernels and specific driver versions for <a href="https://mudongliang.github.io/2016/06/29/install-driver-for-wireless-network-adapter-bcm4352.html" target="_blank">BCM4352</a>: other approaches that used to work don't work anymore.<br />
<br />
Qubes OS maintains a <a href="https://www.qubes-os.org/hcl/" target="_blank">Hardware Compatibility List webpage</a>.<br />
<br />
<h2>
<b>Screenshot of Qubes OS on my laptop</b></h2>
<b><br /></b>
There's still work to do for my VPN proxy setup outside the <i>sys-net</i> VM, <i>vault</i> and other stuff, etc. My typical laptop usage is about surfing the web, watching videos and "accidentally" working (SSH or other remote access approaches).<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtygAL54b675H6NpK-z3bT7PbEJDOLfI3AhQWgDn1Yeq92jsMMqFrpZwdr3iCFFruKdE7UNIYCdeWv2gE7LSxg8NMRqxB1ebpZLkbBys-aNU1oW7vgz3453TwXTe9PeyPg1q8HKA/s1600/qubes_screenshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="1600" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtygAL54b675H6NpK-z3bT7PbEJDOLfI3AhQWgDn1Yeq92jsMMqFrpZwdr3iCFFruKdE7UNIYCdeWv2gE7LSxg8NMRqxB1ebpZLkbBys-aNU1oW7vgz3453TwXTe9PeyPg1q8HKA/s320/qubes_screenshot.png" width="320" /></a></div>
<br />
I tend to prefer Fedora for user programs and Debian for services. I was not successful at setting up other community provided template VMs: <i>build fixes -> build -> install -> startup failures</i><br />
<br />
My ideal final Qubes OS setup would involve the following:<br />
- <a href="https://www.openbsd.org/" target="_blank">OpenBSD</a> as firewall VM, I'm only familiar with <a href="https://www.freebsd.org/" target="_blank">FreeBSD</a> to an extent.<br />
- <a href="https://www.archlinux.org/" target="_blank">Arch Linux</a>, <a href="https://alpinelinux.org/" target="_blank">Alpine</a> or anything else that is lightweight for "proxy/services/servers" VMs.<br />
- A customized <a href="https://dwm.suckless.org/" target="_blank">DWM</a> window manager on DOM0 instead of XFCE to keep it "light": few bash or python scripts to automate small things? On the average day, on DOM0, I just need to attach USB devices, connect to wireless access points and run the Qubes VMs manager.<br />
<br />
<br />
<h2>
Few resources</h2>
<br />
<ul>
<li>The official website: <a href="https://www.qubes-os.org/">https://www.qubes-os.org</a> </li>
<li>The issue tracker: <a href="https://github.com/QubesOS/qubes-issues">https://github.com/QubesOS/qubes-issues</a> </li>
<li>Mailing lists: <a href="https://www.qubes-os.org/support/">https://www.qubes-os.org/support/</a></li>
</ul>
<br />
<br />
<br />
<div>
<br /></div>
Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-75666989630499379772019-06-14T06:26:00.001-07:002019-06-14T06:28:17.625-07:00Recalling when and why I stopped using MS Windows at homeI have used few operating systems over the years. On some occasions, I had the luxury of running a non-Windows OS at the office too (8 years or so).<br />
<br />
<u>At home, I have to confess that I stopped using Windows a "very long time" ago. </u>I do not really play around with any OS since 2007, I'm just the average John Doe doing "simple things" in front of the PC.<u><br /></u><br />
<h2>
<span style="color: blue;"><b>Discovering a non-Windows world</b></span></h2>
Around the end of my bachelor, I realized that there was something called <a href="https://en.wikipedia.org/wiki/Linux" target="_blank">Linux</a> that I didn't know anything about. A friend helped me install it and he showed me some basic commands.<br />
<br />
I was eager to learn and I found all daily tasks challenging at first. How do you find solutions when you don't know the problem or the keywords to type?? I think that many recall Google searches with almost no results, daily forums visits, IRC chats with RTFM comments ☺. <br />
<br />
The fact that .Net was not open-sourced kept me on Linux too, as I quickly started programming in Java during my master. I became a bit obsessed with the command line and discovering a "new world" was very addictive.<br />
<br />
<h3>
The days of the preacher</h3>
At some point, I wanted "help" others switch to Linux. All operating systems have their annoyances in my opinion.<br />
<h3>
</h3>
<h3>
The days of the marginal</h3>
I didn't know many individuals running <u>only Linux</u> in my "bigger entourage".<br />
<ul>
<li>Why don't you use Windows like anybody else?</li>
<li>Where is Internet Explorer? Why isn't StarOffice/OpenOffice just like Microsoft Word? </li>
<li>Why are you often in a terminal?? </li>
<li>Why do you go through so many steps to mount <a href="https://en.wikipedia.org/wiki/NetWare_Core_Protocol" target="_blank">Novell Network drives</a>?</li>
<li>etc.</li>
</ul>
<h3>
</h3>
<h3>
The John Doe days</h3>
My day to day Linux/OSX usage is the same as anybody on Windows. <span style="color: #274e13;">I'm the average John Doe watching videos and browsing the Web, I forgot many things, but there's still lots of muscle memory left</span>. I think that Ubuntu really changed the Linux scene years ago (easier installation, good docs, etc.).<br />
<br />
I occasionally get the "Uh, this is Linux?" and that's it, no real stigma. Most of the tools, that I care about are available on Linux or OSX.<br />
<br />
<h2>
<b><span style="color: blue;">Experimenting with Unix/Linux over the years</span></b></h2>
<span style="color: blue;"><span style="color: black;">At work, I do not always have the choice to use the OS of my liking, I'll run any OS that the client prefers. At home, I stopped running Windows a while ago<b>.</b></span></span><b><span style="color: blue;"><br /></span></b><br />
<h3>
<b>2001-2002 until 2008 - Linux and BSD</b></h3>
My first "real Linux distribution tryout" was Mandrake Linux. In order to become comfortable with Linux I decided to simply wipe my Windows installation. What can you do when you've got no other options :-) ? <i><span style="color: #274e13;">Install it Linux - break it - reinstall - rinse and repeat</span></i><br />
During this period, I tried several distributions (Debian based distros including Ubuntu, Redhat based distributions, Gentoo, Arch Linux, Slackware, etc.).<br />
For a year or so, I run <a href="https://www.freebsd.org/" target="_blank">FreeBSD</a> as my main Desktop OS. I also spent few months on <a href="https://en.wikipedia.org/wiki/Solaris_(operating_system)" target="_blank">Solaris</a>.<br />
<br />
<h3>
<b>2008-2010 - Tasting the $$Apple</b></h3>
I had a <a href="https://en.wikipedia.org/wiki/Hackintosh" target="_blank">Hackintosh</a> for about 2 years (roughly 24 hours of dedication for major releases upgrades -> kernel panics and general issues). I created installation guides to help others, as there was nothing working well for my hardware specs at the time, I won't post any webpage links...<br />
<br />
If you can afford it, I recommend buying Apple products instead of pursuing other ways for running Mac OS. Installing and upgrading a Hackintosh can be tedious, accordingly to your hardware specs.<br />
<br />
<h3>
<b>2012 - 2019</b></h3>
Nowadays, I run OS X on my home-office machine (iMac), as well as Linux (laptop). As of mid 2019, I've been experimenting with <a href="https://www.qubes-os.org/" target="_blank">Qubes OS</a> and other specific purposes distributions.<br />
<br />
<br />
<h2>
<span style="color: blue;"><b>Linux wishes</b></span></h2>
<ul>
<li>It would be great to forget about device drivers (compatibility issues, buggy or unsupported drivers for some hardware).</li>
<li>Missing or unsupported Kernel drivers: My broadcom wireless card is problematic with new Linux kernels and distributions... Depending on the Linux distribution, solving driver issues can be challenging.</li>
<li>Less memory hungry tools: If I recall correctly, I first run a Linux desktop on a 256MB of RAM machine, I'm not sure that this is easily possible anymore.</li>
<li>Recalling tools and conventions across Linux distributions is difficult: switching package managers, tools and conventions is not easy. I'm more comfortable with Debian and Redhat based distributions.</li>
</ul>
<br />
<br />
<br />
<br />
<br />Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-71636398941561827562019-01-14T03:18:00.004-08:002019-01-14T03:18:59.989-08:00Back at itThis blog is alive again! It's been a while and I'm planning on blogging again on a regular basis.<br />Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-32350214036323241932013-08-10T22:39:00.001-07:002013-08-10T22:39:10.620-07:00MovedThis blog has moved to <a href="http://yveszoundi.wordpress.com/">wordpress</a>!<br />
<br />
Please update your bookmarks.Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-77521129022229582032013-07-26T16:10:00.003-07:002013-08-07T14:13:15.318-07:00Review of the Grails Gradle Plugin<p><strong>UPDATE: Using the bootstrap configuration for the Tomcat plugin excludes it from the grails-war task.</strong></p>
<p>See <a href="https://github.com/grails/grails-gradle-plugin/pull/43">https://github.com/grails/grails-gradle-plugin/pull/43</a></p>
<br/>
<a href="http://www.gradle.org/" target="_blank">Gradle</a> support for <a href="http://grails.org/" target="_blank">Grails</a> is maturing slowly and I must say that I can't wait for <a href="http://grails.org/Roadmap" target="_blank">Grails 3.0</a>. "Oh yeah, I'm excited!" :-), almost.<br />
<br />
There are still few bits that I'm not clear about though in terms of how tight the integration will be, not specifically from an IDE usage perspective.<br />
<br />
I watched a presentation from <a href="https://github.com/alkemist" target="_blank">Luke Daley</a> (aka alkemist) <a href="http://www.youtube.com/watch?v=FwZvDU2Jeh8" target="_blank">on Youtube</a>(gr8conf 2013). It showcased the Gradle plugin for building Grails applications using the <a href="https://github.com/grails/grails-gradle-plugin" target="_blank">grails-gradle-plugin</a>.<br />
<br />
I was able to create a small POC and I want to share that experience with you.<br />
<h2>
General notes</h2>
Building a war and running Grails commands? Not a problem.<br />
<i>gradle grails-run-app<usual_grails_command_here></usual_grails_command_here></i><br />
<i>gradle grails-war</i><br />
<br />
You can configure the Grails environment using <i>-PgrailsEnv</i> as<env> command line argument.</env><br />
<i>-Dgrails.env=<env></env></i> or <i>-Pgrails.env=<env></env></i> doesn't seem to work.<br />
<br />
Arguments can be specified using <i>-PgrailsArgs</i><br />
<i>gradle -PgrailsArgs='com.Domain' grails-create-domain-class</i><br />
<br />
For some reason, the <i>grails-gradle-plugin</i> seems to require a closure with a Grails version specified twice (assuming that <u><i>version</i> is only used for bootstrapping the initial call??</u>, while <i>grailsVersion</i> is used for building). I think that it should probably be consolidated...<br />
<pre><code>
grails {
grailsVersion '2.2.3'
version '2.2.3'
}
</code></pre>
<br />
Below is a <i>build.gradle</i> file that does work for the Grails Gradle plugin 2.0.0-SNAPSHOT. Dump the file into some folder and run <b>gradle init</b> first.<br />
<pre><code>
buildscript {
repositories {
mavenCentral()
maven { url 'http://repository.jboss.org/maven2/' }
maven { url 'http://repo.grails.org/grails/repo' }
maven { url 'http://repo.grails.org/grails/plugins' }
maven { url 'http://repository.springsource.com/maven/bundles/release' }
maven { url 'http://repository.springsource.com/maven/bundles/external' }
maven { url 'http://repository.springsource.com/maven/libraries/release' }
maven { url 'http://repository.springsource.com/maven/libraries/external' }
}
dependencies {
classpath 'org.grails:grails-gradle-plugin:2.0.0-SNAPSHOT',
'org.grails:grails-bootstrap:2.2.3'
}
}
version='0.0.1'
apply plugin: 'grails'
repositories {
mavenCentral()
maven { url 'http://repository.jboss.org/maven2/' }
maven { url 'http://repo.grails.org/grails/repo' }
maven { url 'http://repo.grails.org/grails/plugins' }
maven { url 'http://repository.springsource.com/maven/bundles/release' }
maven { url 'http://repository.springsource.com/maven/bundles/external' }
maven { url 'http://repository.springsource.com/maven/libraries/release' }
maven { url 'http://repository.springsource.com/maven/libraries/external' }
}
grails {
grailsVersion '2.2.3'
version '2.2.3'
}
configurations {
all {
exclude module: 'commons-logging'
exclude module: 'xml-apis'
}
test {
exclude module: 'groovy-all'
}
compile {
exclude module: 'hibernate'
}
}
dependencies {
compile( "org.grails:grails-crud:$grails.grailsVersion",
'org.grails:grails-gorm:1.3.7')
bootstrap "org.grails:grails-plugin-tomcat:$grails.grailsVersion"
}</code></pre>
<br />
Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-89885912743411110452013-06-30T16:35:00.000-07:002013-06-30T16:36:26.520-07:00About Java Software Installers and Launchers<div >
<div id="outline-container-sec-1" class="outline-2">
<h2 id="sec-1"><span class="section-number-2">1</span> Introduction</h2>
<div class="outline-text-2" id="text-1">
<p>
In the early stages of your software projects, it's a good practice to think about the distribution aspect.
It doesn't matter how good a product is, if no one can perform the installation or run the application.
</p>
<p>
Generating software installers is not always easy, regardless of the installer product used.
</p>
<p>
If you're lucky enough to have a good commercial software installer, you can generate quickly <a href="http://en.wikipedia.org/wiki/Software_package">packages</a> without too much pain:
</p>
<ul class="org-ul">
<li>Easy generation of application launchers.
</li>
<li>Good default settings with flexibility for splash screens, installer icons, pre-installation/post-installation actions, etc.
</li>
<li>Generation of software packages for a variety of platforms (OSX, Unix, Linux, Windows, etc.).
</li>
</ul>
</div>
</div>
<br/>
<div id="outline-container-sec-2" class="outline-2">
<h2 id="sec-2"><span class="section-number-2">2</span> Application launchers</h2>
<div class="outline-text-2" id="text-2">
<p>
Now that your application development phase is complete, you may be worried about writing couple of launchers.
</p>
<p>
Writing a Java application launcher can become fairly complicated depending on :
</p>
<ul class="org-ul">
<li>The amount of libraries dependencies used by the program.
</li>
<li>The configurations and properties to resolve or create in order to run the application properly.
</li>
<li>Any tasks that need to be executed prior to launching the application.
</li>
</ul>
<p>
For Java based applications, below are the common steps performed by launchers scripts:
</p>
<ul class="org-ul">
<li>Find the Java executable (<code>JAVA_HOME</code> detection if needed, common locations depending on the Operating System).
</li>
<li>Validate the Java version requirements as well as potential optional settings.
</li>
<li>Setup any environment variables or system properties needed by the application.
</li>
<li>Construct the Java classpath from the application dependencies.
</li>
<li>Perform any actions need prior to launching the program.
</li>
<li>Invoke the Java command with the classpath and JVM arguments to start the application.
</li>
</ul>
<br/>
<p>
<a href="http://classworlds.codehaus.org/">ClassWorlds</a> is a simple Java application launcher framework that has been around for a while. It superseeded the <a href="http://mirrors.ibiblio.org/maven2/forehead/forehead/">forehead</a>
framework launcher. Forehead was used by many tools such as Maven (now using ClassWorlds).
</p>
<p>
What makes ClassWorlds compelling is that it's really easy to bootstrap an application launcher without much effort.
All that Classworlds needs is a simple java command that references a boot jar file and your application configuration file(to load libraries).
</p>
</div>
</div>
<div id="outline-container-sec-3" class="outline-2">
<h2 id="sec-3"><span class="section-number-2">3</span> Software Installers and packaging</h2>
<div class="outline-text-2" id="text-3">
<p>
Depending on the application's type, target audience and operating systems, many options are available.
Commercial Software package generators usually provide good results without too much work.
Decent to really good products for Java software packaging include <a href="http://www.flexerasoftware.com/products/installanywhere.htm">InstallAnywhere</a> and <a href="http://www.ej-technologies.com/products/install4j/overview.html">Install4j</a>.
</p>
<p>
Some free Java-oriented installers generators can be found on <a href="http://java-source.net/open-source/installer-generators">java-source.net</a>. A popular choice is <a href="http://izpack.org/">IzPack</a>.
</p>
<p>
Generating software packages by hand <b>still</b> gives you an overall better user's installation experience at the expense of
time and potential bugs (typos, logic errors, etc.).
</p>
<p>
When your installation packages are ready, you then need to test them on all supported platforms, just to be safe.
</p>
<p>
Zip distributions are very convenient for many users:
</p>
<ul class="org-ul">
<li>No administration rights needed most of the time, which is useful when you don't have administrative rights on a machine.
</li>
<li>One step installation, just a matter of extracting a software archive.
</li>
<li>Easy uninstallation which is a simple folder deletion.
</li>
</ul>
<br/>
<p>
When generating software packages, don't forget the simple way of distributing files via zip archives.
</p>
</div>
</div>
</div>
</body>
</html>
Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-21251544612550492252013-06-22T19:23:00.001-07:002013-06-22T19:24:29.660-07:00A good dev Linux Distribution - Fast with many packagesFast with many packages is not the only selection criteria for a Linux distribution, but it's important. "<i>Click and wait... Download manually packages on a regular basis??" -> "no thanks</i>".<br />
<br />
I've used many Linux Distributions over the years: Redhat, Mandriva(previously Mandrake), Debian, Gentoo, Slackware, CentOS, Fedora, Knoppix, Suse, Zenwalk, Ubuntu, etc.<br />
<br />
My main machine at work usually runs some Linux variant. I was lucky enough to always have that luxury since I started to work "<i>As long as you don't need support and you can work with it, you can run Linux on your PC</i>".<br />
<br />
<b>Linux distributions perceived speed</b><br />
Redhat based distributions have to be the slowest around, so I tend not to use them, unless I have to. Among the fastest Linux distros(non minimalistic), I would count in Slackware, Gentoo and few others.<br />
<br />
Today I tried <a href="https://www.archlinux.org/" target="_blank">Arch Linux</a> for the first time. I must say that I'm very much impressed with the raw speed. I would even dare to say that it feels faster than Gentoo or Slackware, without any additional optimization or custom kernel compiled.<br />
<br />
<b>Linux distributions with nice package managers</b><br />
Couple of years ago, RPM based distributions were annoying. It was a real dependency hell depending on where you grabbed your RPM package... Nowadays things are better(yum, etc.), but <u>RPM dependency resolution traumatized me for good</u>...<br />
<br />
As soon as I was introduced to Debian, I never looked back. For a quick install in few minutes Ubuntu will do and for a server a pure Debian distro is nice. Once in a while, I try couple of Linux distributions just for fun.<br />
<br />
Having a nice set of packages available is cool especially when your distribution has a "<i>reliable and powerful</i>" package manager.<br />
<br />
<b>What a dev like me wants from a Linux distro</b><br />
These days, I only need few things from a Linux distro:<br />
<ul>
<li>It has to be fast, as I like to multitask but I also have couple of GB of RAM to spare.</li>
<li>No RPM based distro, <u>Debian or something else</u>. I've always preferred Debian for its <i>apt-get</i> super powers. <i>apt-get</i> has been around for a while and I like it a LOT.</li>
<li>I don't need a graphical installer but I also don't want to a full installation from <i>chroot</i> with tons of steps, unless I have time to kill...</li>
<li>Many packages should be available via the package manager of the distribution, as I try to avoid compiling too many applications.</li>
<li>Flexible installation options (base system vs full desktop/server system). When I have time, I build a system with only what I need...</li>
</ul>
<br />
<div>
<br /></div>
<div>
<br /></div>
Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-22868818891475529232013-06-01T07:43:00.002-07:002013-06-01T07:47:30.530-07:00Maven wrapper project - from Jar library to Maven pluginLast month, the <a href="https://github.com/bdemers/maven-wrapper" target="_blank">maven-wrapper</a> project caught my attention on Github.<br />
<br />
This morning, I had time to kill and I decided to take a closer look at it. I eventually played with it, forked it and added a <i>quick and dirty</i> feature "basic Maven plugin support".<br />
<br />
The <i>maven-wrapper</i> project is a port of the <a href="http://www.gradle.org/docs/current/userguide/gradle_wrapper.html" target="_blank">Gradle wrapper</a> to <a href="http://maven.apache.org/" target="_blank">Maven</a>.<br />
It will download a Maven distribution automatically for you and set it up. Currently the project is just a library, more or less a work in progress at this time.<br />
<br />
Again, I can't emphasize enough on the importance of build tools wrappers, especially on build machines. The release management folks doesn't need to follow any detailed setup guide, nor do they need to worry about managing multiple versions of the same build tools.<br />
<div>
<br /></div>
<b>"Plugin-ifying" the maven-wrapper project</b><br />
I did a <i>very quick and dirty</i> implementation of a Maven plugin, so that the code could be reused as a plugin in new or existing Maven project.<br />
<br />
It was just a matter of adding few dependencies and <a href="http://maven.apache.org/guides/plugin/guide-java-plugin-development.html" target="_blank">writing a simple Mojo</a>.<br />
I eventually renamed the artifactId to have auto-mapping enabled in terms of namespace and goals.<br />
<br />
Nowadays, it's possible to write Mojo descriptors with Java annotations instead of <a href="http://xdoclet.sourceforge.net/xdoclet/index.html" target="_blank">xdoclet</a>-like comments.<br />
<br />
I opened a <a href="https://github.com/bdemers/maven-wrapper/pull/1" target="_blank">pull request</a> to merge the code in the original project few hours ago.<br />
<br />
<b>Maven wrapper plugin usage</b><br />
Checkout the <a href="https://github.com/rimerosolutions/maven-wrapper" target="_blank">maven-wrapper forked project</a> and run the Maven <i>install</i> goal.<br />
<i>mvn install</i><br />
<br />
In another Maven project, add the following to your <i>build->plugins</i> section<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; margin: 0px; padding: 0px;"><build><span style="font-family: Consolas, Liberation Mono, Courier, monospace;"><span style="font-size: 12px;">
<build>
..
<plugins>
..
<plugin>
<groupId>org.apache.maven</groupId>
<artifactId>wrapper-maven-plugin</artifactId>
<version>0.0.1-SNAPSHOT</version>
</plugin>
..
</plugins>
...
</build>
</span></span></build></code></pre>
<b>Maven version compatibility</b><br />
In terms of compilation, it should work with Maven 3.0.2 dependencies and above. The default <a href="https://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/" target="_blank">distribution URL</a> contains some maven versions from 2.0.9 to 3.0.5.<br />
The distribution URL is not customizable automatically at this point (when generating the wrapper supporting files).<br />
<br />
<br />
<b>What would be nice to have in terms of configuration</b><br />
<br />
<ul>
<li>POM driven customization of the default settings (launcher names and location, distribution URL). It's currently possible to do it manually though.</li>
<li>Token substitution inside the plugin when generating wrapper artifacts.</li>
</ul>
<br />
<br />Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com2tag:blogger.com,1999:blog-18565477.post-4547461490697633592013-05-11T23:17:00.000-07:002013-05-12T00:05:34.264-07:00Build Tools WrappersToday I stumbled upon a new project called <a href="https://github.com/bdemers/maven-wrapper" target="_blank">maven-wrapper</a>.<br />
I haven't tested it myself, but it looks like a very promising effort. Users/Developers will be able to perform builds without an existing <a href="http://maven.apache.org/" target="_blank">Maven</a> installation.<br />
<br />
<a href="http://grails.org/doc/2.1.0/guide/single.html#wrapper" target="_blank">Grails</a> and <a href="http://www.gradle.org/docs/current/userguide/gradle_wrapper.html" target="_blank">Gradle</a> already have a way to generate wrappers.<br />
<a href="http://antw.cc/downloads/" target="_blank">Antw</a> seems similar to <a href="http://gvmtool.net/" target="_blank">gvm</a> in terms of concepts and approach.<br />
<br />
Those tools wrappers allow users to build programs without having the software already installed on their local machines.<br />
<br />
This is particularly interesting for build servers, and more specifically <a href="http://en.wikipedia.org/wiki/Continuous_integration" target="_blank">continuous integration</a> servers:<br />
<ul>
<li>Many projects may require different versions of a build tool.</li>
<li>Sometimes the setup of the build tools on a server involves following many processes and getting couple of approvals.</li>
<li>There's a risk of human error that will result into a corrupted non-working software installation (i.e. moving few files around to follow corporate conventions -> broken scripts, file permission issues, etc.).</li>
</ul>
<br />
There are often issues related to build tools in terms of software distribution and usage:<br />
<ul>
<li>People got a copy of the source code, but they don't know how to build it.</li>
<li>The user knows the build tool to use, but he doesn't know how to set it up (Environment variables, PATH manipulation, etc.)</li>
<li>The user knows how to setup the build tool and build the application, but not how to configure the project inside an IDE</li>
<li>etc.</li>
</ul>
<div>
<br />
I expect more and more build tools (as well as full-stack frameworks) to provide the ability to generate <i>seamless</i> wrappers, as it is a very convenient feature.</div>
Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-72568155817493904632013-03-06T02:20:00.003-08:002013-05-11T23:22:59.800-07:00Gradle over Maven for Groovy/Java projects<h2>
<b><span style="font-size: x-large;">* "The Ant" problems</span></b></h2>
For many years, I've been down with <a href="http://maven.apache.org/" target="_blank">Maven</a> and I still am.
In many projects, I've seen some gigantic <a href="http://ant.apache.org/" target="_blank">Ant</a> scripts. Ant has often been a maintenance nightmare in huge applications, fix a script and notice that your eyes are bleeding.<br />
<br />
As "most"corporate developers don't use <a href="http://ant.apache.org/ivy/" target="_blank">Ivy</a> to resolve dependencies with Ant, you typically end up with 3 scenarios:<br />
<br />
<ul>
<li>The dependencies are stored in the version control server, that can get people fired at few places.</li>
<li>There's some kind of repository concept with jars at dedicated locations (Windows shares, NFS, etc.). The dependency resolution involves tons of scripting or some Ant tasks.</li>
<li>Dependencies are stored at a secret location(mapped drive to a Windows share that you'll know about one day) and you can only build after lots of configurations.</li>
</ul>
<br />
Some of the good things about Ant are flexibility, accessibility, documentation. Most developers know how to use Ant and writing custom tasks is not usually hard.<br />
<br />
<h2>
<b><span style="font-size: x-large;">* </span></b><b><span style="font-size: x-large;">Maven</span></b> </h2>
My initial Master thesis subject was supposed to be about Apache Maven, but I bailed out...
If I recall correctly Maven had only beta releases at that time with very little documentation.<br />
<br />
After downloading Maven binaries, I didn't know what to do and how to use it: close to zero documentation and not really "accessible".
When I was about to finish my MBA, I decided to give it another shot. It felt like "I looked at Maven and I got scared...".<br />
<br />
<h3>
<b><span style="font-size: large;">The Jelly Issue</span></b></h3>
<br />
While many people didn't like <a href="http://commons.apache.org/proper/commons-jelly//" target="_blank">Jelly</a>, it provided some basic scripting capabilities inside the build file. If I recall correctly plugins also needed some Jelly files and many developers were annoyed by that constraint.<br />
<br />
<br />
Sometime ago, I wrote an automation tool with Commons Jelly to setup Web hosting on Tomcat.<br />
The tool was a launcher with few relatively small Jelly scripts to perform the following:<br />
<br />
<ul>
<li>Read the list of users from an excel spreadsheet or XML file </li>
<li>Setup FTP accounts </li>
<li>Modify the Tomcat XML files to create application context paths for Web applications </li>
<li>Populate the user information in a database(credentials, ftp and tomcat information)</li>
<li>Send email notifications with the account details.</li>
</ul>
<br />
<br />
Understanding Jelly made my life easier with Maven until it reached 2.x and Jelly was dropped at that time, if I recall correctly.<br />
<br />
<h3>
<b><span style="font-size: large;">Maven evolution</span></b></h3>
With Maven 2.x things got cleaner and more stable, documentation got better and so on. Still many companies didn't give Maven a second chance. Then came Maven 3 and things haven't changed that much at the corporate level.<br />
<br />
Most Java development companies still use Ant and few of them use Ivy to resolve dependencies. I do see Maven here and there, time to time, but not that often.<br />
<br />
<h3>
<b><span style="font-size: large;">Maven adoption</span></b></h3>
From my experience, Maven has always been an issue in non Open-Source projects: too complicated, not worth the effort, too much impact on the typical IDE or build/release workflows.<br />
<br />
While convention over configuration introduces a potential "lack of control" or flexibility, it also have its pros.<br />
<br />
<h2>
<b><span style="font-size: x-large;">* </span></b><b><span style="font-size: x-large;">Gradle to the rescue</span></b></h2>
In the past, I've not really been a big fan of any kind of dynamic or scripting language, unless it's used for scripting or as an extension module. I would probably never have considered <a href="http://www.gradle.org/" target="_blank">Gradle</a> and similar tools in the past, because it would have made me feel "uncomfortable".<br />
<br />
Nowadays, I'm willing to take advantage of <a href="http://groovy.codehaus.org/" target="_blank">Groovy</a>, <a href="http://www.jython.org/" target="_blank">Jython</a>, <a href="http://clojure.org/" target="_blank">Clojure</a> or whatever. <br />
<br />
If I were doing some Clojure, I would try <a href="https://github.com/flatland/cake" target="_blank">cake</a> or <a href="https://github.com/technomancy/leiningen" target="_blank">lein</a> as build tool, unless there's a feature that I need that is only available in Maven. Why? For just 3 main reasons :<br />
- A tool dedicated to a programming language, often means more power and integration.<br />
- There are not many attempts to do too many things or to be too generic, things are easier.<br />
- Having scriptable builds and zero XML is cool.<br />
<br />
<h3>
<b><span style="font-size: large;">Accessible to Java Developers</span></b></h3>
While a Groovy DSL to write a build script is no XML or Java, it's more expressive.<br />
Learning some basic Groovy concepts is easy for Java developers.<br />
<br />
<h3>
<span style="font-size: large;">Solid documentation</span></h3>
I was impressed when I saw the <a href="http://www.gradle.org/docs/1.3/userguide/userguide.html" target="_blank">Gradle manual</a>. It's very good and it's easy to read and understand.<br />
<br />
<h3>
<span style="font-size: large;">Readable files</span></h3>
Last year, after migrating few personal projects from Maven to Gradle, I felt relieved. I didn't have some crazy POM files, but still too much XML to write (or copy/paste).
<br />
The Gradle build files were easier to read/understand with less lines of code.<br />
<br />
<h3>
<b><span style="font-size: large;">Flexibility</span></b></h3>
Adding custom tasks with Groovy Code, without writing plugins unless you need too, this is really nice. If you need plugins there are couple of them out there.<br />
<br />
While there are not as many plugins for Gradle as for Maven, I believe that Gradle is getting more momentum. Many projects such as <a href="https://community.jboss.org/wiki/GradleWhy" target="_blank">Hibernate already switched from Maven to Gradle</a>.Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-21909529299873142412012-12-17T18:59:00.000-08:002012-12-18T15:10:30.038-08:00VFSJFileChooser and XPontus are unmaintained Both <a href="http://vfsjfilechooser.sourceforge.net/" target="_blank">VFSJFileChooser</a> and <a href="http://xpontus.sf.net/" target="_blank">XPontus XML Editor</a> are currently "very inactive", I just needed to make it "very official"!<br />
<br />
Surprisingly, as soon as I stopped working on those projects, I started getting tons of emails related to features requests, bugs or general questions.<br />
<br />
It was a nice run...<br />
<br />
While I may still work on Open Source projects, they will always be small to medium. Nowadays, I focus pretty much all my energy on my Consulting company, <a href="http://www.rimerosolutions.com/" target="_blank">Rimero Solutions</a>.<br />
<br />
Below is the short story of XPontus and VFSJFilechooser.<br />
<br />
<b><span style="font-size: large;">XPontus</span></b><br />
XPontus is probably my most successful project in terms of downloads and interest. Sadly the code was written very late at night without "much love" from an API perspective.<br />
Beer was often around to ease the pain, that's the poor man's truth! I was awake and coding almost all the time...<br />
<br />
<b>Audience and expectations</b><br />
The first release introduced a basic text editor with syntax highlighting, as well as few features for validating and transforming XML. The program was fast and simple.<br />
I started getting feedback quickly as well as many requests about code completion and other missing features.<br />
<br />
Around the last release, I realized that editor was widely used. On <a href="http://sourceforge.net/" target="_blank">Sourceforge</a> there was <a href="http://sourceforge.net/projects/xpontus/files/stats/timeline?dates=2002-12-12+to+2012-12-18" target="_blank">about 30 000 downloads</a>. I would estimate about the same number of combined downloads from many other sites such as <a href="http://freecode.com/projects/xpontus" target="_blank">Freshmeat</a>(now freecode it seems), <a href="http://xpontus.softpedia.com/" target="_blank">Softpedia</a>, etc.<br />
<br />
XPontus was then expected to reach quickly the same level of functionality than <a href="http://www.altova.com/xml-editor/" target="_blank">Altova XML Spy</a> and others. One Open Source Developer against many dedicated Corporate developers...<br />
<br />
<b>Planning</b><br />
It took me a while to get comfortable with Sourceforge. Between research and related coding activities, I kinda rushed things.<br />
<br />
With too many users' requests, I felt like 24h wasn't enough, especially with a full-time on-site job.<br />
<br />
I was still learning some parts of Java Swing while writing the software and I never could perform a full cleanup. I just kept adding new features to please users at the expense of maintenance issues and additional bugs...<br />
<br />
<b>Failure to involve other developers</b><br />
<a href="http://maven.apache.org/" target="_blank">Maven</a> is often an issue among Java Developers. In real life, not that many people are comfortable with it, especially when it's a multi-project module.<br />
<br />
Because the API was a bit crappy and not very flexible, people got discouraged. I also had to answer tons of questions related to design and the various technologies that I was using.<br />
<br />
<b><br class="Apple-interchange-newline" />Support, later on</b><br />
Initially, I generated all the installers manually, more control, but time consuming for testing on many platforms. Later on, <a href="http://www.ej-technologies.com/products/install4j/overview.html" target="_blank">ej-technologies</a> gave me a free license of Install4j while I received a free copy of IntelliJ by <a href="http://www.jetbrains.com/" target="_blank">JetBrains</a>. <a href="http://designapama.blogspot.com/" target="_blank">Apama</a> designed the new XPontus logo.<br />
<br />
<br />
<b>Last effort</b><br />
I attempted a rewrite in late 2009 using <a href="http://www.osgi.org/Main/HomePage" target="_blank">OSGI</a> but I had the impression that it would become a bit like Eclipse Framework, but for Swing.<br />
<br />
The new rewrite was better designed, higher quality but it was too time consuming. I thought about making the project commercial after ensuring that I was using only Apache Licensed libraries.<br />
<br />
I wish that I had the same programming abilities few years ago...<br />
<br />
<span style="font-size: large;"><b>VFSJFileChooser</b> </span><br />
<br />
<b>Audience</b><br />
I always expected VFSJFileChooser to draw interest but not that much. It was a product by a developer and for developers. The library was meant to provide a file dialog component with out-of-the-box remote browsing features.
The project was not much advertised.<br />
<br />
VFSJFileChooser was originally supposed to complement XPontus XML Editor by providing a filesystem abstraction layer. The component was then extracted to make it generic.<br />
<br />
<b>General planning</b><br />
Because it was my second Open Source project, I came prepared.<br />
<br />
I was both organized and I knew my entire Open Source workflow well. My growing Swing experience also helped a lot.<br />
<br />
The scope of the project allowed to be more focused in general. I was more disciplined in terms of programming habits and time allocation.<br />
<br />
<b>Community involvement</b><br />
As it was a relatively small project that used <a href="http://ant.apache.org/" target="_blank">Ant</a> (and not the evil Maven), I received lots of valuable contributions very quickly.<br />
<br />
Some new members joined the team and were were able to get along very quickly. I didn't have to provide any explanations, nor did I answer more than few technical questions.<br />
<br />
We did two releases together, if I recall correctly, and I was really happy about it. I also didn't feel "alone" anymore.<br />
<br />
My life was getting very unbalanced and I was also exploring new career opportunities, so that was pretty much the end of it.<br />
<br />
<b>Other alternatives</b><br />
<ul>
<li><a href="http://code.google.com/p/otrosvfsbrowser/">otrosvfsbrowser</a> is a File browser for Apache Commons VFS version 2. It was created as alternative to "VFS JFileChooser" and "Commons VFS - UI".</li>
<li><a href="http://code.google.com/p/vfsjfilechooser2/">vfsjfilechooser2</a> is a mavenized fork of the dormant vfsjfilechooser project on sf.net.</li>
</ul>Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-45635117781466564942012-12-08T16:37:00.001-08:002012-12-08T17:30:39.787-08:00emacs-grails-mode enhancementsI'm now using <a href="http://www.gnu.org/software/emacs/" target="_blank">Emacs</a> again as my main Anything (Text Editing, Mail Reading, Blogging, Chat, etc.).<br /><br/>I still use vi and IDEs randomly but I will dedicate more time to <em>master Emacs</em> (don't quote me on that...) and a bit of <a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)" target="_blank">Lisp</a>.
<br /><br/>
I was looking for some Emacs packages for <a href="http://grails.org/" target="_blank">Grails</a> Development and I found <a href="https://github.com/kurtharriger/emacs-grails-mode" target="_blank">emacs-grails-mode</a>.<br />
It's nice, but it doesn't seem to provide few things such as running a random Grails command against a project.<br />
<br />
During development, most of the time I'm jumping between files using <a href="https://github.com/technomancy/find-file-in-project/blob/master/find-file-in-project.el" target="_blank">find-file-in-project.</a> Occasionally, I use few functions provided by <em>emacs-grails-mode</em> to switch between files associated to Grails domain classes.<br /><br/>
Then, whenever I want to run a Grails command, I switch to a dedicated shell buffer. I read the output and I jump back to the file(s) that I'm working on...
<br /><br/>
I'm no Lisp coder which is a bit sad from my perspective. If I were fluent with it, I could write couple of Emacs packages or improve few things for my personal taste.<br />
<br /><br />
Below is my first attempt to improve emacs-grails-mode. I will soon create a basic project on <a href="https://github.com/rimerosolutions">my corporate GitHub account</a> and push the code there. The license will be GPL v3.<br /><br/>
I added the following extensions to <em>emacs-grails-mode</em>.
<ul>
<li>Few functions to run some Grails commands from the project folder.</li>
<li>There are are also 3 functions to browse API docs, Wiki docs as well as the latest reference guide.</li>
</ul>
<br /><br/>
<pre style='color:#000000;background:#ffffff;'><span style='color:#696969; '>;; ================================</span>
<span style='color:#696969; '>;; Extensions for grails-mode</span>
<span style='color:#696969; '>;; Author : Yves Zoundi</span>
<span style='color:#696969; '>;; Created : 08-Dec-2012</span>
<span style='color:#696969; '>;; </span>
<span style='color:#696969; '>;; License: GNU GPL v3 (http://www.gnu.org/licenses/gpl-3.0.txt)</span>
<span style='color:#696969; '>;; Sypnosis:</span>
<span style='color:#696969; '>;; Run grails command on a project</span>
<span style='color:#696969; '>;;</span>
<span style='color:#696969; '>;; TODO:</span>
<span style='color:#696969; '>;; - Add some easy keybindings like in Rinari</span>
<span style='color:#696969; '>;; - Would be nice if auto-completion was there</span>
<span style='color:#696969; '>;; (including dynamic methods)</span>
<span style='color:#696969; '>;; - Anything else that would be useful for Grails development</span>
<span style='color:#696969; '>;; ================================</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>require</span> <span style='color:#800080; '>'grails-mode</span><span style='color:#808030; '>)</span>
<span style='color:#696969; '>;; --------------------------------</span>
<span style='color:#696969; '>;; Main functions</span>
<span style='color:#696969; '>;; --------------------------------</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>command <span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>str</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Run a Grails command (Non interactive)"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>project-ensure-current</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>setq</span> shell-command-initial-directory
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>project-default-directory</span> <span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>project-current</span><span style='color:#808030; '>)</span><span style='color:#808030; '>)</span><span style='color:#808030; '>)</span>
<span style='color:#696969; '>;; store old directory</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>setq</span> old-dir default-directory<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>setq</span> command-initial-directory
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>expand-file-name</span> shell-command-initial-directory<span style='color:#808030; '>)</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>cd</span> command-initial-directory<span style='color:#808030; '>)</span>
<span style='color:#696969; '>;; runs the grails command from the project directory</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>async-shell-command</span> <span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>concat</span> <span style='color:#0000e6; '>"grails "</span> str<span style='color:#808030; '>)</span> <span style='color:#7d0045; '>nil</span> <span style='color:#7d0045; '>nil</span><span style='color:#808030; '>)</span>
<span style='color:#696969; '>;; restore previous directory</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>cd</span> old-dir<span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>read-param-and-run <span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>input-hint</span> grails-command<span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Read an input parameter and invoke a given Grails command"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>setq</span> grails-command-argument
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>read-from-minibuffer</span> input-hint<span style='color:#808030; '>)</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>grails/command</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>concat</span> grails-command <span style='color:#0000e6; '>" "</span> grails-command-argument<span style='color:#808030; '>)</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#696969; '>;; --------------------------------</span>
<span style='color:#696969; '>;; General functions</span>
<span style='color:#696969; '>;; --------------------------------</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>icommand <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Enter a Grails command (Interactive)"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>grails/read-param-and-run</span> <span style='color:#0000e6; '>"Goal:"</span> <span style='color:#0000e6; '>""</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>create-domain <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Create a Grails Domain Class"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>grails/read-param-and-run</span>
<span style='color:#0000e6; '>"Domain class:"</span> <span style='color:#0000e6; '>"create-domain-class"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>create-controller <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Create a Grails Controller"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>grails/read-param-and-run</span>
<span style='color:#0000e6; '>"Controller Domain class:"</span> <span style='color:#0000e6; '>"create-controller"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>create-service <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Create a Grails Service"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>grails/read-param-and-run</span>
<span style='color:#0000e6; '>"Service Domain class:"</span> <span style='color:#0000e6; '>"create-service"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>create-taglib <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Create a Grails Taglib"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>grails/read-param-and-run</span>
<span style='color:#0000e6; '>"TagLib Name:"</span> <span style='color:#0000e6; '>"create-tag-lib"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#696969; '>;; --------------------------------</span>
<span style='color:#696969; '>;; Plugin functions</span>
<span style='color:#696969; '>;; --------------------------------</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>install-plugin <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Install a Grails plugin"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>grails/read-param-and-run</span>
<span style='color:#0000e6; '>"name optionalversion:"</span> <span style='color:#0000e6; '>"install-plugin"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>uninstall-plugin <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Uninstall a Grails plugin"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>grails/read-param-and-run</span>
<span style='color:#0000e6; '>"Plugin Name:"</span> <span style='color:#0000e6; '>"uninstall-plugin"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>package-plugin <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Package a Grails plugin"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>grails/command</span> <span style='color:#0000e6; '>"package-plugin"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>refresh-dependencies <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Refresh Grails Dependencies"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>grails/command</span> <span style='color:#0000e6; '>"refresh-dependencies"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#696969; '>;; --------------------------------</span>
<span style='color:#696969; '>;; Browse docs (api, wiki, guide)</span>
<span style='color:#696969; '>;; --------------------------------</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>browse-wiki-docs <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Browse the Wiki Documentation"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>browse-url</span> <span style='color:#0000e6; '>"http://grails.org/Documentation"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>browse-api-docs <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Browse the API Documentation"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>browse-url</span> <span style='color:#0000e6; '>"http://grails.org/doc/latest/api/"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>defun</span> grails<span style='color:#808030; '>/</span>browse-latest-guide <span style='color:#808030; '>(</span><span style='color:#808030; '>)</span>
<span style='color:#0000e6; '>"Browse the official Grails Guide"</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>interactive</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>browse-url</span> <span style='color:#0000e6; '>"http://grails.org/doc/latest/guide/single.html"</span><span style='color:#808030; '>)</span>
<span style='color:#808030; '>)</span>
<span style='color:#808030; '>(</span><span style='color:#800000; font-weight:bold; '>provide</span> <span style='color:#800080; '>'emacs-grails-mode-ext</span><span style='color:#808030; '>)</span>
</pre>Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-82253899318520360482012-10-27T21:08:00.003-07:002012-10-28T07:51:54.232-07:00A quick look at Apache Karaf<br />
<br />
<br />
Today, I decided to take a brief look at <a href="http://karaf.apache.org/">Apache Karaf</a>. Apache Karaf is an <a href="http://en.wikipedia.org/wiki/OSGi">OSGI</a> runtime that embeds <a href="http://felix.apache.org/site/index.html">Apache Felix</a> as OSGI container. It ships with couple of OSGI bundles and provides a nice shell interface.<br />
<br />
I am not really covering some technical details in this post. I haven't deployed an application under Karaf yet, as I would want to do a bit more than the typical "Hello World".<br />
<br />
<b><span style="font-size: large;">My previous OSGI experience in context</span></b><br />
Few years ago, I was trying to understand OSGI and I created an OSGI based IRC bot, called <a href="http://sand-irc.sourceforge.net/">Jerkbot</a>. Prior to that experience, OSGI looked inaccessible, unpopular with a low return value. Even after reading couple of OSGI articles, I still couldn't figure out 100% what to do with it.<br />
<br />
<b>Building Jerkbot</b><br />
Within a day, I was able to deal with most of the bot features. I went quickly over Apache Felix tutorials and I was ready to write some code.<br />
<br />
<ul>
<li>As soon I introduced a persistence layer, I hit minor issues with <a href="http://en.wikipedia.org/wiki/Java_Persistence_API">JPA</a>(classloading). After struggling with <a href="http://openjpa.apache.org/">OpenJPA</a> and <a href="http://hibernate.org/">Hibernate</a>, I settled with <a href="http://www.eclipse.org/eclipselink/">EclipseLink</a>.</li>
<li>I used mainly <a href="http://www.eclipsezone.com/eclipse/forums/t96740.html">Declarative Services</a> with annotations to save time, instead of writing couple of BundleActivators and/or XML descriptors.</li>
<li>SpringSource had a Maven repository with <i>OSGIfied</i> jars, so I used it instead of wrapping every single non OSGI jar</li>
</ul>
<br />
My build process involved the following :<br />
<br />
<ul>
<li>Run the Maven install goal at the root of the multi-module project</li>
<li>Copy all the files with rsync from my desktop to a laptop running FreeBSD (<applicationhome>/<jars_folder>)</jars_folder></applicationhome></li>
<li>Setup the Apache Felix configuration to specify the startup order of each bundle depending on what I was testing</li>
<li>Start Apache Felix from the command line with my configuration</li>
</ul>
<br />
Alternatively, I could update the bundles within the Apache Felix console without restarting the program sometimes.<br />
<br />
<b>Packaging</b><br />
When the time came to actually shipping the application, I was annoyed. I had to write a Maven assembly configuration to package the application as a zip file. After playing with couple of deployment options, I had generated few temporary folders and it became difficult to identify what was still needed.<br />
<br />
I ended up only shipping source code, as the <a href="http://www.ops4j.org/projects/pax/construct/maven-pax-plugin/">PAX Maven plugin</a> could run the application from the project tree.<br />
<br />
If I recall correctly Karaf already existed, as <a href="http://icodebythesea.blogspot.ca/2011/01/brief-history-of-apache-karaf.html">mentioned in a blog post about Apache Karaf history</a>. I believe that I did look at it, but not in details. I probably couldn't figure out quickly whether or not it would be worth it (read 2 paragraphs and give a yes/no/maybe answer).<br />
<br />
<b>Application Frond-end</b><br />
As the bot itself had a <a href="http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html">JMX</a> interface, I could just use JConsole to hook into the bot admin interface. I wasn't really planning on hooking up some Apache Felix commands.<br />
With Karaf, the <a href="http://karaf.apache.org/manual/2.2.5/developers-guide/extending-console.html">shell extension process</a> seems similar to <a href="http://felix.apache.org/site/61-extending-the-console.html">the one provided by Apache Felix</a>.<br />
<br />
<br />
<b><span style="font-size: large;">Discovering Karaf</span></b><br />
<b><span style="font-size: large;"><br /></span></b>
I was really impressed by the product's features and usability. Below are some of the topics that got my interest.<br />
<br />
<b>Installation</b><br />
<a href="http://karaf.apache.org/manual/latest-2.2.x/quick-start.html">Installing Karaf</a> on my iMac was pretty straightforward. The only problem that I run into was launching the <a href="https://karaf.apache.org/manual/2.2.5/users-guide/web-console.html">webconsole</a> as soon as I installed it. I got a <i>NullPointerException</i> and I just restarted Karaf. I guess that some initialization logic is probably missing in the bundle activation or something related.<br />
<br />
<b>Documentation</b><br />
I usually don't read much technical documentation. The Karaf folks did a decent job with the user guide. I found myself scrolling and jumping only to topics of interest.<br />
<br />
<b>Console</b><br />
The console is really neat with tab completion. The contextual help for each command is brief and easy to grasp.<br />
<br />
<b>Deployment</b><br />
In additional to standard OSGI bundles, Karaf also includes support for wrapping non OSGI jar files. I guess that they achieved that with some integration with the <a href="http://www.aqute.biz/Bnd/Bnd">BND</a> tool. What really surprised me was the Maven integration in addition to standard deployment options : <a href="http://stackoverflow.com/questions/9414375/karaf-development">http://stackoverflow.com/questions/9414375/karaf-development</a><br />
<br />
It is also possible to configure the available Maven repositories: <a href="https://cwiki.apache.org/KARAF/66-installing-additional-features.html">https://cwiki.apache.org/KARAF/66-installing-additional-features.html</a><br />
<br />
<b>Remoting</b><br />
Apache Karaf exposes couple of JMX MBeans, it has a nice Web Console and SSH access is also supported.<br />
<br />
<b>Security</b><br />
Karaf developers really made a decent effort here. The <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html">JAAS</a> integration seems rather smooth in addition to basic encryption services. I found a blog with a JAAS module example and I didn't expect it to be that easy <a href="http://iocanel.blogspot.ca/2010/09/karafs-jaas-modules-in-action.html">http://iocanel.blogspot.ca/2010/09/karafs-jaas-modules-in-action.html</a><br />
<br />
<b>Opened questions (running foreground)</b><br />
If I recall correctly, it is possible to start Apache Felix in the foreground by specifying a config property (embedded or something). I didn't figure out how to do it with Karaf, but I didn't search a lot.<br />
<br />
<br />
<b><span style="font-size: large;">Conclusion</span></b><br />
I easily see myself using Apache Karaf on side projects in the near future. It provides many features out of the box that would require the following :<br />
<br />
<ul>
<li>Adding couple of bundles to the OSGI container manually</li>
<li>Writing few modules to support administration services with additional options. Especially with you can grab few OSGI bundles here and there that I only provide basic functionalities(Felix config/admin bundles, PAX bundles, etc.).</li>
</ul>
<br />
I still don't seem much OSGI adoption even though there are more articles and tutorials available. I believe that Apache Karaf makes OSGI somehow more "accessible". However, the OSGI adoption in the corporate world is very slow from what I see. OSGI needs more simplicity, more mediatization, more real life examples to reach many companies' doors.<br />
<br />
<br />
<b><span style="font-size: large;">References</span></b><br />
<br />
<ul>
<li><a href="http://www.anova.be/files/OSGi%20with%20Apache%20Felix%20Karaf.pdf">http://www.anova.be/files/OSGi%20with%20Apache%20Felix%20Karaf.pdf</a></li>
<li><a href="https://karaf.apache.org/manual/2.2.5/users-guide/index.html">https://karaf.apache.org/manual/2.2.5/users-guide/index.html</a></li>
<li><a href="http://www.liquid-reality.de/pages/viewpage.action?pageId=131134">http://www.liquid-reality.de/pages/viewpage.action?pageId=131134</a></li>
<li><a href="https://cwiki.apache.org/KARAF">https://cwiki.apache.org/KARAF</a></li>
<li><a href="http://felix.apache.org/site/index.html">http://felix.apache.org/site/index.html</a></li>
</ul>
<br />Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-86777971084790612902012-03-24T12:07:00.002-07:002012-03-24T18:45:11.221-07:00GWT in general and the CellTree widget I've been toying a bit with GWT and it's quite nice.<br />
<br />
In the past, I've used many frameworks to some extent, <i>depending on what was needed</i> : raw JSP with or without JSTL, Struts, VRaptor 1.x, Cocoon, JSF, Velocity, Wicket, etc. <br />
I had more fun using Wicket than something like Struts 1.x for example... <br />
I never liked Struts but it seemed good enough compared to other frameworks at the time(Early ASP.NET versions were already more usable for medium size apps). If I were <i>compelled</i> to use something similar to <a href="http://struts.apache.org/">Struts</a> today, with the luxury of choice, I would likely select <a href="http://www.stripesframework.org/display/stripes/Home">Stripes</a> or another technology close to it (simple but flexible).<br />
Overall, I've always preferred component based Web Frameworks to the Actions based ones.<br />
<br />
<b>A) GWT and its UI frameworks (more than UI usually)</b><br />
<a href="http://www.sencha.com/products/extgwt">GXT</a> and others such as <a href="http://www.smartclient.com/product/smartgwt.jsp">SmartGWT</a> seem to be much slower than raw GWT for rendering but it is <i>expected</i> as the default look and feel looks good without any effort. The default look and feel is cool.<br />
<br />
I stumbled upon GXT buttons rendering. While the buttons are VERY beautiful, the amount of nested elements required for rendering is almost incredible.<br />
<br />
<br />
<b>1) Normal HTML</b><br />
<pre><input type="button" value="OK" class='dummyClass' />
</pre><br />
<b>2) GXT (dummy example to illustrate the problem) </b><br />
<pre><table cellspacing="0" role="presentation"
class="x-btn x-component x-btn-noicon" id="x-auto-175"
style="margin-right: 5px;">
<tbody class="x-btn-small x-btn-icon-small-left">
<tr>
<td class="x-btn-tl">
<i> </i>
</td>
<td class="x-btn-tc"></td>
<td class="x-btn-tr">
<i> </i>
</td>
</tr>
<tr>
<td class="x-btn-ml">
<i> </i>
</td>
<td class="x-btn-mc">
<em unselectable="on" class="">
<button style="position: relative; width: 69px;"
type="button" class="x-btn-text" tabindex="0">
Save</button>
</em>
</td>
<td class="x-btn-mr">
<i> </i>
</td>
</tr>
<tr>
<td class="x-btn-bl">
<i> </i>
</td>
<td class="x-btn-bc"></td>
<td class="x-btn-br">
<i> </i>
</td>
</tr>
</tbody>
</table>
</pre><br />
The above example was taken from <a href="http://my.opera.com/lienngoc/blog/2010/08/10/how-to-improve-performance-in-a-gwt-gxt-application">http://my.opera.com/lienngoc/blog/2010/08/10/how-to-improve-performance-in-a-gwt-gxt-application</a> and is realistic enough.<br />
<br />
<b>B) GWT CellTree</b><br />
The GWT CellTree is a very nice widget. I managed to use it with RPC calls within a small amount of time and minimal reading.<br />
<br />
<b>1) Rendering</b><br />
I was expecting to be able to provide easily a custom renderer and that was the case. In the GWT showcase, for each level of the tree, the same kind of node is rendered which means a single renderer at each level of the tree. I was like well, it is just an 'example'. In real life, you usually have objects of different kinds at the same level of a tree and they need to be rendered differently. <br />
<br />
I ended up using a single renderer and calling <i>instanceof</i> to select the appropriate styling for each node of the tree. I couldn't find another solution within a short amount of time.<br />
<pre class="brush: java">public void render(Context context, MyObject value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendHtmlConstant((value instanceof MyBaseObject) ? baseImgHTML : advancedImgHTML).appendEscaped(" ");
sb.appendHtmlConstant("<span class='cssClassForNode'>");
sb.appendEscaped(value.toString());
sb.appendHtmlConstant("</span>");
}
}
</pre><br />
<b>2) Can I haz vertical scrollbars???</b><br />
After testing a simple application, I noticed that Google Chrome was displaying a vertical scrollbar while I was expanding the CellTree nodes. Firefox didn't render any scrollbars.... I came accross a stackoverflow link, and for a second I thought 'this is it!', I guess it would've been too easy...<br />
<a href="http://stackoverflow.com/questions/7854086/horizontal-scrollpanel-not-displaying-with-celltree">http://stackoverflow.com/questions/7854086/horizontal-scrollpanel-not-displaying-with-celltree</a><br />
<br />
After 'googling' a bit and Firebug's help, I found a solution.<br />
<u>1. Add few CSS style attributes to the CellTree and its parent container </u><br />
The celltree has the following CSS style : width:100%;height:100%;overflow:auto. It is enclosed within an HTMLPanel with the same CSS style. There's no need to combine a <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/user/client/ui/ScrollPanel.html">ScrollPanel</a> with let's say a <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/user/client/ui/VerticalPanel.html">VerticalPanel</a>. Same problem and additional widgets used.<br />
<u><br />
</u><br />
<u>2. Ensure that the first element has a visible overflow and a dummy size in pixels</u><br />
I didn't test it with a small tree, but I figure that as long as you supply a dummy size that will always be lower than the height of a non empty tree, it'll be fine. I used 100px.<br />
<pre class="brush: java">Style firstCellTreeChildStyle = cellTree.getElement().getFirstChildElement().getStyle();
firstCellTreeChildStyle.setOverflow(Overflow.VISIBLE);
firstCellTreeChildStyle.setHeight(100, Unit.PX);
</pre><br />
<b>C) Overall opinion about pure GWT vs GWT frameworks</b><br />
<br />
It looks like building a professional looking pure GWT application requires a serious commitment in terms of styling widgets. For medium-small applications, I think that using a framework will give good looking results with less time without many performance issues.Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-71634096015136725022011-06-19T09:03:00.000-07:002011-06-19T09:03:35.164-07:00Playing with Apache Cocoon 3.0 - Part 2<span class="Apple-style-span" style="font-family: inherit;">As couple of people requested a complete example, I uploaded the full source file, as well as some sample input files, everything but the jar files </span><a href="https://rapidshare.com/files/3196609858/dist.zip"><span class="Apple-style-span" style="font-family: inherit;">here</span></a><span class="Apple-style-span" style="font-family: inherit;">.</span><br />
<span class="Apple-style-span" style="font-family: inherit;"><br />
</span><br />
<b><span class="Apple-style-span" style="font-family: inherit;">About the upload</span></b><br />
<br />
<ul><li><span class="Apple-style-span" style="font-family: inherit;">The uploaded file is called </span><i><span class="Apple-style-span" style="font-family: inherit;">dist.zip</span></i><span class="Apple-style-span" style="font-family: inherit;"> (MD5: d930916c8506bdc563925385e7aa1162) and contains 2 folders : </span><i><span class="Apple-style-span" style="font-family: inherit;">src</span></i><span class="Apple-style-span" style="font-family: inherit;"> and </span><i><span class="Apple-style-span" style="font-family: inherit;">www</span></i><span class="Apple-style-span" style="font-family: inherit;">. </span></li>
<li><span class="Apple-style-span" style="font-family: inherit;">The </span><i><span class="Apple-style-span" style="font-family: inherit;">src</span></i><span class="Apple-style-span" style="font-family: inherit;"> folder contains the Java source file </span></li>
<li><span class="Apple-style-span" style="font-family: inherit;">The </span><i><span class="Apple-style-span" style="font-family: inherit;">www</span></i><span class="Apple-style-span" style="font-family: inherit;"> folders contains all the files needed to generate a simple website. I didn't provide the exact files that I used for privacy reasons.</span></li>
</ul><br />
<b><span class="Apple-style-span" style="font-family: inherit;">Dependencies</span></b><br />
<span class="Apple-style-span" style="font-family: inherit;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: inherit;">You can grab the required Jar dependencies from Maven repositories(click on the hyperlinks below) :</span><br />
<br />
<br />
<ul><li><a href="http://repo1.maven.org/maven2/org/apache/cocoon/controller/cocoon-controller/3.0.0-alpha-2/cocoon-controller-3.0.0-alpha-2.jar"><span class="Apple-style-span" style="font-family: inherit;">cocoon-controller-3.0.0-alpha-2.jar</span></a></li>
<li><a href="http://repo1.maven.org/maven2/org/apache/cocoon/pipeline/cocoon-pipeline/3.0.0-alpha-2/cocoon-pipeline-3.0.0-alpha-2.jar"><span class="Apple-style-span" style="font-family: inherit;">cocoon-pipeline-3.0.0-alpha-2.jar</span></a></li>
<li><a href="http://repo1.maven.org/maven2/org/apache/cocoon/sax/cocoon-sax/3.0.0-alpha-2/cocoon-sax-3.0.0-alpha-2.jar"><span class="Apple-style-span" style="font-family: inherit;">cocoon-sax-3.0.0-alpha-2.jar</span></a></li>
<li><a href="http://repo1.maven.org/maven2/org/apache/cocoon/sitemap/cocoon-sitemap/3.0.0-alpha-2/cocoon-sitemap-3.0.0-alpha-2.jar"><span class="Apple-style-span" style="font-family: inherit;">cocoon-sitemap-3.0.0-alpha-2.jar</span></a></li>
<li><a href="http://cocoon-stringtemplate-3.0.0-alpha-2.jarhttp://repo1.maven.org/maven2/org/apache/cocoon/stringtemplate/cocoon-stringtemplate/3.0.0-alpha-2/cocoon-stringtemplate-3.0.0-alpha-2.jar"><span class="Apple-style-span" style="font-family: inherit;">cocoon-stringtemplate-3.0.0-alpha-2.jar</span></a></li>
<li><a href="http://www.apache.org/dist/xml/cocoon/BINARIES/cocoon-xml-2.0.2.jar"><span class="Apple-style-span" style="font-family: inherit;">cocoon-xml-2.0.2.jar</span></a></li>
<li><a href="http://mirrors.ibiblio.org/pub/mirrors/maven/commons-logging/jars/commons-logging-1.1.jar"><span class="Apple-style-span" style="font-family: inherit;">commons-logging-1.1.jar</span></a></li>
<li><a href="http://dist.wso2.org/maven2/xerces/xercesImpl/2.9.1/xercesImpl-2.9.1.jar"><span class="Apple-style-span" style="font-family: inherit;">xercesImpl-2.9.1.jar</span></a></li>
<li><a href="http://mirrors.ibiblio.org/pub/mirrors/maven2/xml-apis/xml-apis/1.3.04/xml-apis-1.3.04.jar"><span class="Apple-style-span" style="font-family: inherit;">xml-apis-1.3.04.jar</span></a></li>
<li><a href="http://mirrors.ibiblio.org/pub/mirrors/maven/xalan/jars/xalan-2.7.1.jar"><span class="Apple-style-span" style="font-family: inherit;">xalan-2.7.1.jar</span></a></li>
<li><span class="Apple-style-span" style="font-family: inherit;"><a href="http://mirrors.ibiblio.org/pub/mirrors/maven/mule/dependencies/maven2/xerces/xml-serializer/2.7.1/xml-serializer-2.7.1.jar">xml-serializer-2.7.1.jar</a></span></li>
</ul><div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><b><span class="Apple-style-span" style="font-family: inherit;"><br />
</span></b></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><b><span class="Apple-style-span" style="font-family: inherit;">Running the application</span></b></div><ul><li>Create an Java project with the IDE of your choice and add the source file and the required dependencies(jar files).</li>
<li><span class="Apple-style-span" style="font-family: inherit;">In the main method of the class <i>StaticSiteGenerator</i>, change the variable</span><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: inherit;"> <span class="Apple-style-span" style="font-size: small;"><i>wwwRoot</i> to point the the folder </span></span><span class="Apple-style-span" style="font-family: inherit;"><span class="Apple-style-span" style="font-size: small;"><i>www</i></span></span><span class="Apple-style-span" style="font-family: inherit;"><span class="Apple-style-span" style="font-size: small;"> folder extracted from the </span></span><span class="Apple-style-span" style="font-family: inherit;"><span class="Apple-style-span" style="font-size: small;"><i>dist.zip</i></span></span><span class="Apple-style-span" style="font-family: inherit;"><span class="Apple-style-span" style="font-size: small;"> archive.</span></span></span></span></li>
<li><span class="Apple-style-span" style="font-family: inherit;">Run the class and the output will be generated in the </span><span class="Apple-style-span" style="font-family: inherit;"><i>www/out</i></span><span class="Apple-style-span" style="font-family: inherit;"> folder in HTML format.</span></li>
</ul></div>Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-32006566997931870352011-04-09T15:07:00.000-07:002013-05-11T23:23:33.242-07:00Playing with Apache Cocoon 3.0This morning, I needed to generate quickly a simple website without learning some template engine or recalling it.<br />
<br />
I was thinking about couple of years ago when I was working a lot with <a href="http://cocoon.apache.org/">Apache Cocoon</a> and XML processing in general.<br />
<br />
I downloaded the <a href="http://cocoon.apache.org/3.0/download.html">latest build of Cocoon 3.0 alpha 2</a> and gave it a shot. Below are my settings for the site generation :<br />
<br />
<ul>
<li>Input folder containg XML files (root element and html content)</li>
<li>Toc file for site navigation (xml + html markup)</li>
<li>Resources to include </li>
<li>An XSL stylesheet for the website generation (dynamic include of the TOC)</li>
</ul>
<div>
The site was ready after few minutes and minor adjustments. It looks like there's a <a href="https://issues.apache.org/jira/browse/COCOON3-50">bug in the XIncludeTransformer </a>so I couldn't use it with the alpha 2 version.</div>
<div>
<br /></div>
<div>
Below is some quick and dirty code(all in one class, without other files used) written after downloading it. There are some errors(generics and invalid content) in the code below because of the code formatter that I'm using on this blog.</div>
<pre class="brush: java">import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.transform.OutputKeys;
import org.apache.cocoon.pipeline.NonCachingPipeline;
import org.apache.cocoon.pipeline.Pipeline;
import org.apache.cocoon.sax.SAXPipelineComponent;
import org.apache.cocoon.sax.component.XMLGenerator;
import org.apache.cocoon.sax.component.XMLSerializer;
import org.apache.cocoon.sax.component.XSLTTransformer;
// Simple website generation demo with Apache Cocoon 3.0 alpha2
public final class StaticSiteGenerator {
// Generator configuration parameters
private static enum SiteConfiguration {
INPUT_FOLDER_LOCATION,
OUTPUT_FOLDER_LOCATION,
WEBSITE_XSL_STYLESHEET_LOCATION,
RESOURCES_FOLDER_LOCATION,
TOC_FILE_LOCATION,
INPUT_FILES_EXTENSION
}
// Error thrown when the configuration appears to be invalid
private static class InvalidConfiguration extends RuntimeException {
private static final long serialVersionUID = -8661543651471092797L;
public InvalidConfiguration(String message) {
super(message);
}
}
// Parameter passed to the XSL stylesheet to include a navigation bar
private static final String TOC_FILE_XSLT_PARAMETER_NAME = "tocURL";
// Current link in the TOC
private static final String TOC_FILE_CURRENT_LINK = "currentLink";
// Copy a file to a folder
static void copyToFolder(File in, File outputFolder) throws IOException {
File out = new File(outputFolder, in.getName());
FileChannel inChannel = new FileInputStream(in).getChannel();
FileChannel outChannel = new FileOutputStream(out).getChannel();
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
}
catch (IOException e) {
throw e;
}
finally {
if (inChannel != null) inChannel.close();
if (outChannel != null) outChannel.close();
}
}
// Generator configuration parameters
private EnumMap<siteconfiguration string=""> configuration;
// Creates a new <code>StaticSiteGenerator</code> with a given configuration
StaticSiteGenerator(EnumMap<siteconfiguration string=""> configuration) {
validateConfiguration(configuration);
this.configuration = configuration;
}
// Simple configuration validation
private void validateConfiguration(EnumMap<siteconfiguration string=""> configuration) throws InvalidConfiguration {
if (configuration == null) {
throw new IllegalArgumentException("You must provide a valid configuration");
}
Collection<siteconfiguration> allConfigurations = new ArrayList<siteconfiguration>(Arrays.asList(SiteConfiguration.values()));
Collection<siteconfiguration> providedConfigurations = new ArrayList<staticsitegenerator .siteconfiguration="">(configuration.keySet());
allConfigurations.removeAll(providedConfigurations);
if (!allConfigurations.isEmpty()) {
StringBuilder sb = new StringBuilder(allConfigurations.size() * 3);
sb.append("Some configuration parameters were not found:");
SiteConfiguration[] missingConfigurations = allConfigurations.toArray(new SiteConfiguration[allConfigurations.size()]);
sb.append(missingConfigurations[0]);
for (int i = 1; i < missingConfigurations.length; i++) {
sb.append(", ").append(missingConfigurations[i]);
}
throw new InvalidConfiguration(sb.toString());
}
}
private void clean(File outputFolder) {
for (File outputFile : outputFolder.listFiles()) {
outputFile.delete();
}
}
// Generates the static web site
private void execute() throws Exception {
final File inputFilesFolder = new File(configuration.get(SiteConfiguration.INPUT_FOLDER_LOCATION).toString());
final File outputFolder = new File(configuration.get(SiteConfiguration.OUTPUT_FOLDER_LOCATION).toString());
final File resourceFolder = new File(configuration.get(SiteConfiguration.RESOURCES_FOLDER_LOCATION).toString());
final File xslStylesheet = new File(configuration.get(SiteConfiguration.WEBSITE_XSL_STYLESHEET_LOCATION).toString());
final String inputFilesExtension = configuration.get(SiteConfiguration.INPUT_FILES_EXTENSION).toString();
final File tocFile = new File(configuration.get(SiteConfiguration.TOC_FILE_LOCATION).toString());
clean(outputFolder);
final String tocURL = tocFile.getAbsolutePath();
// Get the list of XML files for each page of the website
File[] inputFiles = inputFilesFolder.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(inputFilesExtension) && pathname.isFile();
}
});
File[] resources = resourceFolder.listFiles();
// Copy resources to the output folder
for (File resource : resources) {
copyToFolder(resource, outputFolder);
}
// Loop through the input files
for (File inputFile : inputFiles) {
OutputStream outputFileStream = null;
String msg = "Transforming '%s' to '%s'";
try {
String outputFilename = inputFile.getName().replaceAll(inputFilesExtension, ".html");
File outputFile = new File(outputFolder, outputFilename);
Logger.getAnonymousLogger().log(Level.INFO, String.format(msg, inputFile.getAbsolutePath(), outputFile.getAbsolutePath()));
outputFileStream = new FileOutputStream(outputFile);
Pipeline<saxpipelinecomponent> pipeline = new NonCachingPipeline<saxpipelinecomponent>();
pipeline.addComponent(new XMLGenerator(inputFile.toURI().toURL()));
pipeline.addComponent(newXSLTransformer(xslStylesheet, tocURL, outputFilename));
pipeline.addComponent(newXMLSerializer());
pipeline.setup(outputFileStream);
pipeline.execute();
}
finally {
if (outputFileStream != null) outputFileStream.close();
}
}
}
private XMLSerializer newXMLSerializer() {
Properties format = new Properties();
format.put(OutputKeys.METHOD, "xml");
format.put(OutputKeys.INDENT, "yes");
return new XMLSerializer(format);
}
private XSLTTransformer newXSLTransformer(File stylesheet, String tocFileURL, String currentLink) throws MalformedURLException {
Map<string object=""> parameters = new HashMap<string object="">(1);
parameters.put(StaticSiteGenerator.TOC_FILE_XSLT_PARAMETER_NAME, tocFileURL);
parameters.put(StaticSiteGenerator.TOC_FILE_CURRENT_LINK, currentLink);
XSLTTransformer transformer = new XSLTTransformer(stylesheet.toURI().toURL());
transformer.setParameters(parameters);
return transformer;
}
public static void main(String[] args) throws Exception {
String wwwRoot = "/Users/yves/Desktop/www";
EnumMap<siteconfiguration string=""> configuration;
configuration = new EnumMap<staticsitegenerator .siteconfiguration="" string="">(StaticSiteGenerator.SiteConfiguration.class);
configuration.put(SiteConfiguration.INPUT_FOLDER_LOCATION, wwwRoot + "/in");
configuration.put(SiteConfiguration.INPUT_FILES_EXTENSION, ".xml");
configuration.put(SiteConfiguration.TOC_FILE_LOCATION, wwwRoot + "/toc/toc.xml");
configuration.put(SiteConfiguration.OUTPUT_FOLDER_LOCATION, wwwRoot + "/out");
configuration.put(SiteConfiguration.WEBSITE_XSL_STYLESHEET_LOCATION, wwwRoot + "/resources/xsl/site.xsl");
configuration.put(SiteConfiguration.RESOURCES_FOLDER_LOCATION, wwwRoot + "/resources/files");
StaticSiteGenerator generator = new StaticSiteGenerator(configuration);
generator.execute();
}
}
</staticsitegenerator></siteconfiguration></string></string></saxpipelinecomponent></saxpipelinecomponent></staticsitegenerator></siteconfiguration></siteconfiguration></siteconfiguration></siteconfiguration></siteconfiguration></siteconfiguration></pre>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-70299119147654581812010-09-30T04:57:00.000-07:002010-09-30T04:57:41.798-07:00Flex annoyances...Can I grabz the initialz focuz?I've been playing a bit with <a href="http://en.wikipedia.org/wiki/ActionScript">ActionScript</a> and the like lately. ActionScript and few other languages never really caught my interest. Sure, I can read and I could manage, but why? ;-).<br />
<br />
In fact, I've been avoiding Perl, ActionScript and few others professionally for years: <br />
Q:"So you know Java, Quartz, JMX, Unix/Linux, etc. what about Perl?" <br />
A:"Oh my, to be honest, I'm afraid of it...".<br />
Sometimes, you just have to suck it up and do the damn thing anyway.<br />
<br />
It's surprising to me that Flex is used a lot for "<em>intensive</em>" tasks, that <em>would/should</em> require threads to poll data at specific intervals. What else would you use if you need a decent toolkit with <em>advanced</em> drawing capabilities on the browser? A beloved Java Applet? Silverlight? HTML5? Javascript?? ActiveX???<br />
<br />
<a href="http://www.adobe.com/products/flex/">Flex</a> has some interesting things despite being single threaded(not the flash engine itself) : function pointers, easy binding, easy drag and drop, etc. However, some simple to more complex things can become annoying, while with more code, but still simple code, the same thing would be trivial with a Desktop UI toolkit(that you're familiar with).<br />
<ul><li>Can I be sure that a <em>return</em> inside a <em>switch</em> statement will just <em>return, at once</em>?</li>
<li>Can I get the initial focus on a component once the flash movie is loaded, without keyboard interaction from my part? without random errors once in a while? without upgrading to bleeding edge?</li>
<li>Can I get a simple even bare layout manager interface without plugging stuff directly inside some <em>updateDisplayList</em> method? Or without managing myself couple of "<em>drawing delegates</em>"?</li>
<li>etc...</li>
</ul><br />
It looks like Flex has couple of issues with its FocusManager. <strong>All I wanted was setting the focus on a component at startup with a blinking cursor... Trivial right?</strong><br />
<br />
I was looking for an answer on Google as many seem to have that issue. I found a suggestion that seem to work : <br />
<em>ExternalInterfaceIfAvailable.call(SomeJavascript.focusFlashComponent).</em> <br />
<em>callLater(mycomponent.grabTheFocus)</em><br />
<br />
<u>Lots of people seem to be ok with the fact that the Javascript that they write might not work on most browsers</u>. Well, good enough if only a defined set of browsers will be supported by the application.<br />
But hey man, this is 2010, most web applications are past the time where a notice would be displayed "Only supported in Internet Explorer". Unless this is the web interface of your online banking accounts, you switch to an alternative immediately."Sorry man, I do not use Windows, so how could I use I.E??".<br />
<br />
I just grabbed the latest version of <a href="http://www.prototypejs.org/">prototypejs</a> and I'm confident that the code compatible with most modern browsers(and even maybe text based browsers that support a little subset of Javascript). Why not write it myself? Well I don't do tons of Javascript, and looking at browsers specs and compatibility with Javascript versions might not be worth the time. From prototypejs to <a href="http://jquery.com/">JQuery</a> and the like, people already did the dirty work.<br />
<br />
<strong>Let's say that the Javascript code is working</strong>, now you're able to set the initial focus on a component once the flash <em>movie</em> is loaded. In my case, the component that need the focus is added/removed at runtime. <br />
<br />
When going back to the initial screen, <em>Flex 3.4 throws randomly errors in the FocusManager</em>. It looks like that FocusManager bug got fixed(<em>defaultButton</em> issue), but my solution was to deactivate/activate the FocusManager myself :<br />
<ul><li>Initial screen</li>
</ul>onCreationComplete -> javascript call to set the focus -> Specific flex component requests then the focus<br />
<ul><li>Leaving the initial screen(Avoid some null errors on the <strong>defaultButton</strong> if you use that)</li>
</ul><em>component.focusmanager.deactivate()</em><br />
<ul><li>Going back to the initial screen(Avoid some null errors on the <strong>defaultButton</strong> if you use that)</li>
</ul><em>mycodeToGrabTheFocus</em><br />
<em>component.focusmanager.activate()</em>Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-11084671013529813342009-12-29T16:33:00.000-08:002009-12-29T17:35:56.924-08:00Default right-click in all text components of an application<p>First of all, Merry Christmas and Happy New Year everybody!</p><div>Many people are still surprised not to see a default right-click popup in all text components of a Java application. One way to do it, is to push a new <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/awt/EventQueue.html">EventQueue</a> to the default one. One concern could be applets in general (unsigned applets, global EventQueue).</div><pre code="java">Toolkit.getDefaultToolkit().getSystemEventQueue().push(new PopupEventQueue());<br /></pre>Below is the code for the event queue.<pre class="brush: java"><br />import java.awt.AWTEvent;<br />import java.awt.Component;<br />import java.awt.EventQueue;<br /><br />import java.awt.event.ActionEvent;<br />import java.awt.event.MouseEvent;<br /><br />import javax.swing.AbstractAction;<br />import javax.swing.JPopupMenu;<br />import javax.swing.SwingUtilities;<br /><br />import javax.swing.text.JTextComponent;<br /><br />public class PopupEventQueue extends EventQueue {<br /><br />private final JPopupMenu popup = new JPopupMenu();<br />private final TextAction[] popupActions = new TextAction[4];<br /><br />public PopupEventQueue() {<br /> popupActions[0] = new TextAction("Cut") {<br /> private static final long serialVersionUID = -3844049016540352208L;<br /><br /> public void actionPerformed(ActionEvent ae) {<br /> textComponent.cut();<br /> }<br /><br /> @Override<br /> protected void postTextComponentInitialize() {<br /> setEnabled(textComponent.isEditable() && isTextSelected());<br /> }<br /> };<br /> popupActions[1] = new TextAction("Copy") {<br /> private static final long serialVersionUID = -3844049016540352208L;<br /><br /> public void actionPerformed(ActionEvent ae) {<br /> textComponent.copy();<br /> }<br /><br /> @Override<br /> protected void postTextComponentInitialize() {<br /> setEnabled(isTextSelected());<br /> }<br /> };<br /> popupActions[2] = new TextAction("Paste") {<br /> private static final long serialVersionUID = -3844049016540352208L;<br /><br /> public void actionPerformed(ActionEvent ae) {<br /> textComponent.paste();<br /> }<br /><br /> @Override<br /> protected void postTextComponentInitialize() {<br /> setEnabled(textComponent.isEditable());<br /> }<br /> };<br /> popupActions[3] = new TextAction("Select all") {<br /> private static final long serialVersionUID = -3844049016540352208L;<br /><br /> public void actionPerformed(ActionEvent ae) {<br /> textComponent.selectAll();<br /> }<br /><br /> @Override<br /> protected void postTextComponentInitialize() {<br /> setEnabled(!textComponent.getText().trim().equals(""));<br /> }<br /> };<br /><br /> for (TextAction action : popupActions) {<br /> popup.add(action);<br /> }<br />}<br /><br />@Override<br />protected void dispatchEvent(AWTEvent event) {<br /> if (event.getID() == MouseEvent.MOUSE_RELEASED) {<br /> MouseEvent e = (MouseEvent) event;<br /><br /> Component c = getSource(e);<br /><br /> if (c instanceof JTextComponent) {<br /> if (SwingUtilities.isRightMouseButton(e)) {<br /> final JTextComponent txtComp = (JTextComponent) c;<br /> for (TextAction action : popupActions) {<br /> action.setTextComponent(txtComp);<br /> }<br /> popup.show(e.getComponent(), e.getX(), e.getY());<br /> }<br /> }<br /> }<br /> super.dispatchEvent(event);<br />}<br /><br />private Component getSource(MouseEvent e) {<br /> return SwingUtilities.getDeepestComponentAt(<br /> e.getComponent(),<br /> e.getX(),<br /> e.getY());<br />}<br /><br />private static abstract class TextAction extends AbstractAction {<br /><br /> private static final long serialVersionUID = -7708937505251885197L;<br /> protected JTextComponent textComponent;<br /><br /> public TextAction(String name) {<br /> super(name);<br /> }<br /><br /> public void setTextComponent(JTextComponent textComponent) {<br /> this.textComponent = textComponent;<br /> postTextComponentInitialize();<br /> }<br /><br /> protected boolean isTextSelected() {<br /> return (textComponent.getSelectionStart() != textComponent.getSelectionEnd());<br /> }<br /><br /> protected abstract void postTextComponentInitialize();<br />}<br />}<br /></pre>Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com2tag:blogger.com,1999:blog-18565477.post-52384395578712115182009-08-24T05:58:00.001-07:002009-08-24T05:58:12.492-07:00The making of an OSGI based IRC Bot<p style="clear: both">I've released the source code of <a href="https://sand-irc.svn.sf.net/svnroot/sand-irc/jerkbot/" title="JerkBot SVN repository" target="_blank">JerkBot</a>, an IRC bot based on <a href="http://jerklib.sf.net" target="_blank">Jerklib</a> and <a href="http://www.osgi.org/" title="OSGI main site" target="_blank">OSGI</a>. JerkBot source code is a multi-module maven project. It's not some OSGI/Java blueprints as I'm no OSGI expert, plus JerkBot is basically a 24 hours effort without bug fixes.</p><p style="clear: both">The library itself is distributed under BSD license, but the bot provides plugins such as SVN for example using <a href="http://svnkit.com/" target="_blank">SVNKit</a> , which is subject to other licensing terms.</p><p style="clear: both">The bot uses <a href="http://www.eclipsezone.com/eclipse/forums/t96740.html" title="Declarative Services intro" target="_blank">Declarative Services</a> for OSGI and Java technologies such as :</p><p style="clear: both"><ul style="clear: both"><li><a href="http://lucene.apache.org/java/docs/" target="_blank">Apache Lucene</a> for Javadoc Search</li><li><a href="http://www.opensymphony.com/quartz/" title="Quartz website" target="_blank">Quartz</a> for job scheduling(session tracking, pending registrations, etc.)</li><li><a href="http://java.sun.com/products/javamail/" title="Javamail Website" target="_blank">Javamail</a> to send emails for user registration</li><li><a href="http://www.eclipse.org/eclipselink/" target="_blank">EclipseLink</a> for persistence</li><li>A subset of <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/tutorials/GeneralAcnOnly.html" title="Old guide" target="_blank">JAAS</a> for security</li><li><a href="http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/" title="JMX website" target="_blank">JMX</a> for administrative commands (accessible through <a href="http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html" title="Tutorial on JConsole" target="_blank">JConsole</a> or through the bot <em>jmx</em> command)</li><li>The usual <a href="http://commons.apache.org/" target="_blank">Jakarta libraries</a> and couple of other libraries</li></ul></p><p style="clear: both">I didn't provide scripting languages to the bot for security reasons, there's only JMX. I would prefer to offer scripting languages in a secure way with a custom <a href="http://java.sun.com/docs/books/tutorial/essential/environment/security.html" target="_blank">SecurityManager</a> to prevent drama from happening :-). <br />Let's say scripting is enabled, and someone accidently tries one or all the following instructions in a scripting language.</p><p style="clear: both"><ul style="clear: both"><li>File("/somepath").delete()</li><li>System.exit(0)</li><li>Download("http://website/hugefile.iso").saveToDisk();</li></ul><br />JerkBot was roughly a one day effort with 4 rewrites(1 full day each), and of course bug fixes time to time:<br /><ul style="clear: both"><li>The first version was using traditional OSGI, well not so traditional :-), with <a href="http://www.osgi.org/javadoc/r4v41/org/osgi/framework/BundleActivator.html" target="_blank">BundleActivators</a> service trackers and listeners, etc.</li><li>The second rewrite used <a href="http://felix.apache.org/site/apache-felix-service-component-runtime.html" target="_blank">Declarative Services</a> with manually written XML descriptors</li><li>The third rewrite was based on Felix <a href="http://felix.apache.org/site/ipojo-concepts-overview.html" title="IPojo Website" target="_blank">IPOJO</a>. I would have preferred to use IPOJO, but found some annoyances(abstract based classes, JMX flexibility, etc.).</li><li>The last rewrite is using <a href="http://felix.apache.org/site/apache-felix-maven-scr-plugin.html" target="_blank">Felix SCR but with annotations</a> to generate XML descriptors for components. Simplify code, remove unnecessary abstractions, consistent logic, etc.</li></ul></p><p style="clear: both">I'll be providing the binary distribution soon. The binary distribution contains everything necessary to run the bot : OSGI configuration files, Bot configuration, jars, a user/developer guide, etc.</p><p style="clear: both">What the bot doesn't provide is a logging mechanism, for IRC channel logs. To do it right, I think it would be better to create a new project. In my opinion, when a bot logs channel it should have, if possible, the following features:<br /><ul style="clear: both"><li>Configurable tasks to schedule<em> flexible timed </em>delivery of existing logs(local filesystem, ftp, samba share, ssh, http put, etc.)</li><li>Configurable log format(HTML, CSV, TXT) with optional generation of html logs or text logs.</li><li>Database storage or any other persistence mechanism(Apache Lucene Index vs flat text files, database logs, etc.)</li><li>Ability to stop/start logging for every channel</li><li>Optional Web front-end to publish logs(Could be a static HTML pages with Javascript search, JSF, Wicket, GWT, Rest interface + Apache Lucene or a DB for search).<br /></li></ul>Providing a quick and dirty plugin for channel logs would be trivial <em>but not flexible</em> :-). I started implementing it, but I decided to stop there.</p><p style="clear: both">The first draft of the bot manual can be found in the <a href="http://sand-irc.svn.sf.net/viewvc/sand-irc/jerkbot/jerkbot-manual.pdf" target="_blank">svn repository</a>. Please bear with me for grammar and spelling mistakes, it was a written <em>very quickly at early AM</em> :-)</p><p style="clear: both">In JerkBot plugins are provided by OSGI bundles. I learned a lot from my previous experience with <a href="http://jpf.sf.net" target="_blank">JPF</a> when writing <a href="http://xpontus.sf.net" target="_blank">XPontus</a>.<br /><br />For now the bot is sitting on irc.freenode.net in the ##swing channel, running on an old laptop(FreeBSD-CURRENT).</p><br class='final-break' style='clear: both' />Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com6tag:blogger.com,1999:blog-18565477.post-45445480726011639332009-07-22T16:45:00.001-07:002009-07-22T16:48:25.729-07:00Which one is the best?<p style="clear: both">You've probably heard it many times, in various circumstances. What was your answer? </p><p style="clear: both">That trivial question may(or not) have been subject to a long answer with hopefully credible reasons. "The problem is ... Many tools provide XXX ... This tool is the best, in this case, as ...".<br />But you're the expert! The reasons motivating your choices should be obvious to anybody else without having a long discussion!</p><p style="clear: both"><strong>There is no best</strong>, there are needs and there are constraints to reach particular goals(short, medium or long term). All those variables usually fits in to a vision. <strong><br /></strong></p><p style="clear: both"><strong>If there were a best, anyone who could afford it, would have it</strong>. <em><br /></em></p><p style="clear: both"><em>No, no why would I want to use crap seriously?? So many tools already suck and people keep providing more crap. Maybe I should suggest that they stop already, as there are many similar great tools out there.</em></p><p style="clear: both"><u>A typical conversation about choosing a Linux distribution</u><br />Q: "What's the best Linux distribution? Ubuntu?"<br />A: "Wut??? Hell no, it's Debian and all the rest is crap including the derivatives."<br />Q: "Why?"<br />A: "Because Ubuntu doesn't ... and because I say so :-)"<br />Q: "But Ubuntu is easy and Debian is not user friendly!"<br />A: "Really? Not really .... Ah, I guess I just like things when they're complicated, must be the geek feeling."</p><p style="clear: both">A tool can meet needs but not all the constraints and vice-versa and what you'll probably be looking for is a balance.</p><p style="clear: both"></p><ul style="clear: both"><li>Memory usage vs tons of features</li><li>Usability vs complexity/too much flexibility</li><li>Easily understood vs require 5 books + certification + hiring a consultant</li><li>Commercial support vs community support</li><li>Proven stability and acceptance vs the unknown </li><li>etc.</li></ul><p></p><p style="clear: both">There are simple ways to decide :<br /></p><ul style="clear: both"><li>You have a problem to address within constraints(time, budget, etc.)</li><li>You try looking for tools which are particularly good at solving your specific problem and that integrate perfectly in your custom infrastructure. However, no such tools seem to exist or there's that little thing that you dislike.</li><li>You then look for compromises and ways to solve the issues that won't get magically fixed by the tools. </li><li>You don't have time to look at all the existing tools and evaluate them. You'll be selecting few tools and trying them out. Hopefully software vendors will cover the tiniest details which are relevant to your business needs, in their documentation.</li><li>You decide and you live with it, maybe reevaluate your decision and revise your goals, but you move forward unless you really believe that you're wrong.<br /></li></ul><br />It's not easy to decide in the IT world. You might get it right or wrong but you may have the power to correct your mistakes. Whatever the choice, the rational move is trying to select wisely, going forward and take responsibility.<p></p>Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-57283004689535277712009-07-14T17:08:00.000-07:002009-07-14T17:46:31.659-07:00Playing with OSGI and JPAI've been writing an <a href="http://en.wikipedia.org/wiki/Internet_Relay_Chat">IRC</a> bot for fun, but it's far from being done. My goal is to experiment with <a href="http://java.sun.com/javaee/overview/faq/persistence.jsp">JPA</a> in an <a href="http://www.osgi.org/About/Technology">OSGI</a> environment. <div><br /></div><div>At work, I am using Hibernate, XDoclet to generate the XML and JPA isn't coming soon :-). My last JPA application was a <a href="http://pastebin.ca">pastebin</a> application, with <a href="http://wicket.apache.org/">Wicket</a>, hibernate search, Lucene, etc. <div><div><div><br /></div><div>I'm using a friend's library <a href="http://jerklib.sourceforge.net/">Jerklib</a> with <a href="http://www.dynamicjava.org/projects/dynamic-jpa">Dynamic JPA</a>. I'm still having some minor issues when deploying but I'll probably find a solution soon.</div><div><br /></div><div><b>About the application</b></div><div><b><i>Environment</i></b></div><div>I have a multi-project with Maven and I'm using the maven bundle plugin and I'm developing in Eclipse 3.5 on Debian testing.</div><div>I'm using <a href="http://openjpa.apache.org/">openjpa</a> , dynamic jpa and couple of other dependencies</div><div><br /></div><div><b><i>Design overview</i></b></div><div>a) Commands implemented as plugins : The bot has a set of factoids(learn, forget, etc...). Each command gets created using a factory.</div><div><br /></div><div><code></code></div><code><div></div><span><span>// message listener //String operation = getOperation();</span></span></code><div><code><span><span>CommandFactory factory = ServiceFromOSGI.getCommandFactory(operation);</span></span></code></div><div><span class="Apple-style-span" style="font-family:monospace, fantasy;font-size:100%;"><span class="Apple-style-span" style="font-size: 13px;"><br /></span></span></div><div><code><span><span>// if the factory is not null, redundancy for the operation parameter</span></span></code></div><div><code><span><span>// as a factory can have multiple commands</span></span></code></div><div><code><span><span>Command command = factory.createCommand(operation);</span></span></code></div><div><code><span><span>ircChannel.say(command.render(ircMessageContext));</span></span></code><div><div><br /></div><div>b) The command service listens for removal or installation of commands and updates itself.</div><div><br /></div><div>After writing couple of "users' commands", I would need to implement some administration commands(load/unload plugins, irc specific tasks, etc.).</div><div><br /></div><div><b><i>Problems</i></b></div><div>The dynamic discovery is failing for now, the persistence provider class is not resolved, it might just be a bundling problem for openjpa. I wrapped it myself.</div><div><br /></div><div><b>Conclusion</b></div><div> It's strange that many open source projects still don't provide an OSGI manifest. The <a href="http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html">maven-bundle plugin</a> is very trivial to use for maven enabled project and there's still <a href="http://www.aqute.biz/Code/Bnd">bnd</a>.</div><div> While OSGI is an interesting technology, I personally don't know anybody using it in the enterprise unless they are an Eclipse shop. I think that it's mostly due to </div><div><ul><li>the lack of "OSGI enabled jars"</li><li>the fear that OSGI might introduce unnecessary complexity</li><li>the lack of step by step complete examples(if possible with screencasts)</li></ul></div><div><br /></div><div>There's plenty of documentation about OSGI and lots of successful applications(Web, Desktop) using OSGI. Hopefully my bot will be one those applications :-)</div><div><br /></div></div></div></div></div></div>Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-51492136924486303582009-03-21T21:02:00.001-07:002009-03-21T21:02:29.765-07:00Thoughts about JavaFX<p><a href="http://javafx.com/">JavaFX</a> has the potential to become something interesting. While there are many articles written about JavaFX, I have yet to see a non trivial JavaFX application. When browsing <a href="http://www.dzone.com/">Dzone</a> articles, it almost looks like JavaFX is popular, while it's not.</p><br /><p>There's no amazing UI control and I am not sure that I could code an entire JavaFX application without writing few java classes. I am not fond of applets and I haven't written any for years. JavaFX doesn't solve the "applet problem".</p><br /><p>I don't know about any cellular phone which is officially supporting JavaFX. I am also not aware of any software vendor distributing desktop applications written with that technology.</p><br /><p>In my opinion, JavaFX is not ready for production use. What motivated the release of JavaFX? Maybe they've been advertising it for too long and <em>they had to release something</em>. I'll give JavaFX probably one more year before attempting to use it.</p><br /><br />Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-32227474320317804702009-01-04T10:06:00.001-08:002009-01-04T10:42:04.826-08:00serialVersionUID in NetbeansMost of the time, I use <a href="http://netbeans.org/">Netbeans</a> when I have the choice. What I don't like about <a href="http://eclipse.org/">Eclipse</a> and is getting me worried time to time is when the IDE freezes for a long time when you're not really doing anything.<br /><br />Last week, I needed to build a simple Java project (<a href="http://maven.apache.org">Maven</a> based build), about 50 000 lines of code(from <a href="http://www.dwheeler.com/sloccount/">sloccount</a>). The project contains one core project and few sub projects. Eclipse took about 30 minutes to import the project and set up the classpath. That performance was achieved under a Quad Core, 2 GB of RAM, which is amazing. I had only Eclipse, Firefox and a terminal opened. I tried with both <a href="http://code.google.com/p/q4e/">q4e</a> and <a href="http://m2eclipse.codehaus.org/">m2eclipse</a> plugins, same results, I could hear my CPU making lots of noise. I had time to start cooking, boil water for coffee and do some other things, before the IDE was ready to use.<br /><br />One of many missing features in Netbeans is the ability to generate the serial version ID for a serializable class. With Eclipse, you get the warning all the time, and you can choose between:<br /><ul><li>ignoring it</li><li>adding the annotation<span style="font-weight: bold;"> @SuppressWarning("serial")</span></li><li>generating the serial version id.</li></ul><br /><span style="font-weight: bold;">Available plugins for Netbeans</span><br />There are two plugins available for Netbeans, that I am aware of : <a href="http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=9000">UUIDGenerator</a> and <a href="http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=6887">serialVersionUID generator</a>. I only have success with <span style="font-style: italic;">UUIDGenerator</span> (most of the time, I am running the latest development build under Linux and Windows and lately Mac OS Leopard).<br /><br /><span style="font-weight: bold;">Enabling Serialization warnings</span><br />Under Tools->Options->Editor->Hints->Standard Javac warnings, select Serialization. That way, you'll see a marker notifying you that you're missing the declaration of a serialVersionUID field.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1RX-6KAAfLVcQ3ge_xegXANrVAnvBH6qeaGD8dmAz0gMwEKlbqj0mbmvtlayDTkmOv04DzgHk5Q5M35uO3VpgKTPD0SP-Nb7sPQKoI9ZRZ9et9VY9kRmOjf4NTrAPz4O9XCc0Ig/s1600-h/serialsettings.png"><img style="cursor: pointer; width: 320px; height: 215px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1RX-6KAAfLVcQ3ge_xegXANrVAnvBH6qeaGD8dmAz0gMwEKlbqj0mbmvtlayDTkmOv04DzgHk5Q5M35uO3VpgKTPD0SP-Nb7sPQKoI9ZRZ9et9VY9kRmOjf4NTrAPz4O9XCc0Ig/s320/serialsettings.png" alt="" id="BLOGGER_PHOTO_ID_5287508776711677538" border="0" /></a><br /><br /><br /><span style="font-weight: bold;">Generate the serial version ID</span><br />You can generate the serialVersionUID using the shortcut <span style="font-style: italic;">Control-ALT-Z</span>. You can copy the generated contents to the clipboard and paste it inside your class.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjZJ3_2dPfMwCvXbVlP0R2gIkG-741XQ45HzcjuIzi1GCwbVnHAa_ZVzqLwGe3cO8ofFAHKPseUXy-C2XZNTcFO57XxYcntCqlSiqLPopcHYEuyPzRA-WGtkS8ThAuFSYkK8rsFw/s1600-h/serialuuid.png"><img style="cursor: pointer; width: 288px; height: 229px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjZJ3_2dPfMwCvXbVlP0R2gIkG-741XQ45HzcjuIzi1GCwbVnHAa_ZVzqLwGe3cO8ofFAHKPseUXy-C2XZNTcFO57XxYcntCqlSiqLPopcHYEuyPzRA-WGtkS8ThAuFSYkK8rsFw/s320/serialuuid.png" alt="" id="BLOGGER_PHOTO_ID_5287508326391920770" border="0" /></a>Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com3tag:blogger.com,1999:blog-18565477.post-2003493806985314252008-12-23T19:17:00.001-08:002008-12-23T19:26:40.331-08:00Merry Christmas<a href="http://xpontus.sf.net">XPontus</a> and <a href="http://vfsjfilechooser.sf.net">VFSJFileChooser </a>were released this evening. I wanted to release before Christmas! Still the same stress and anxiety before and after publishing a new version. Now, I need to start advertising in forums, etc. <div><br /><div>The last few days, well more nights than days, have been mostly about testing XPontus installers, fixing bugs, reviewing as much code as I could. </div><div><br /></div><div>Merry Christmas everybody and happy new year!</div></div>Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com0tag:blogger.com,1999:blog-18565477.post-86578292319347140022008-11-25T20:02:00.000-08:002008-11-25T21:38:45.824-08:00Handling database changes without complete migration<span style="font-weight: bold;">The ORM market</span><br /><a href="http://en.wikipedia.org/wiki/Object-relational_mapping">ORM</a> tools are great. Products like <a href="http://www.hibernate.org">Hibernate</a>, <a href="http://java.sun.com/jdo/index.jsp">JDO</a>, <a href="http://java.sun.com/javaee/overview/faq/persistence.jsp">JPA</a>, <a href="http://ibatis.apache.org/">IBATIS</a>, <a href="http://db.apache.org/torque/">Torque</a>, and others made life easier for developing database enabled applications.<br />Using <a href="http://java.sun.com/javase/6/docs/technotes/guides/jdbc/">JDBC</a> when your application is database intensive with lots of table can be lots of work especially if lots of your existing code base doesn't provide some DAO classes.<br />Usually in ORM tools, you map a set of fields to some columns, using <a href="http://www.w3.org/XML/">XML</a> or <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html">annotations</a>, and you're done.<br /><br />Most J2EE and core Java developers have faced database changes and migration issues at least once. The problem is pretty crucial when your database model is shared by other applications which can't be upgraded(for many reasons).<br /><br /><span style="font-weight: bold;">The concern</span><br /><ul><li>How to handle database changes which keep happening?</li><li>Should/Could you stop providing backward compatibility?</li><li>Is upgrading the database model your only solution?<br /></li></ul><span style="font-weight: bold;">The application history</span><br /><ul><li>You have an existing application with a model which has been designed carefully and everything is going well.</li><li>You have a server side application with a database model and client applications with the same database model as the "main server".<br /></li><li>A month or a year later, you need to make lots of changes in couple of tables, replace some primary keys, introduce some non null foreign keys, etc.</li><li>You were using raw JDBC mostly and plain SQL. Now, you would like to use that brand new bleeding edge technology(Hibernate, JPA, Ibatis, name it).<br /></li><li>Here and there, you might have been using a very old ORM tool which was convenient at the time and is still getting the job done.<br /></li></ul><span style="font-weight: bold;">Constraints</span><br /><ul><li>You need to be able to support simultaneously clients(applications) running older and newer versions of the database schema.</li><li>You cannot force the customer to upgrade for many reasons(hardware dependencies, partner application compatibility, the customer doesn't want to, etc.)</li><li>You need to keep adding new features which might involve altering again the existing schema</li><li>Your table contents are now messed up, invalid or irrelevant values here and there because the database column has a "NOT NULL" property.<br /></li></ul><span style="font-weight: bold;">Possible solutions</span><br /><ul><li>One might be tempted to maintain different versions of the same database, but let's say I have 100 versions since 1994.</li><li>Ok, let's use <a href="http://jcp.org/en/jsr/detail?id=170">JCR</a> to provide another abstraction level, maybe checking a node property before deciding which class to map, overkill in most cases?<br /></li><li>"Dear customer, please, upgrade and buy the new pack to be able to use that version which also provide bug fixes and new features"<br /></li><li>Hum... last resort "Dear customer, you should upgrade because that X, Y, W feature fixes lots of serious security holes which will affect your network"</li><li>Ok, from now on, every table will be like a key-pair, probably not very wise most of the time, especially if it will involve rewriting most parts of a huge application.<br /></li></ul><span style="font-weight: bold;">The problem is here, a fix must be delivered!<br /></span>What I would probably do is :<br /><ul><li>Stick with raw SQL and migrate ORM mappings to JDBC, as needed(if the ORM tools cannot ommit fields), to ignore some properties depending on the client database version. I can insert some dummy values when I have no choice when dealing with "old software clients".<br /></li><li>Use native SQL queries and JDBC only</li><li>Use named SQL queries with binding and anything tool that supports it Hibernate, Ibatis, a resultset handler from <a href="http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/jdbc/core/JdbcTemplate.html">JdbcTemplate</a> or <a href="http://commons.apache.org/dbutils/">DbUtils</a>, etc. Some dummy data will need to be inserted when not available(new non null columns).<br /></li><li>If the problem gets out of hand, way too many changes, I'll probably want to use a non relational database and handle relationships myself(An object or XML database might do, but might not scale)<br /></li><li>Another solution, would be JCR. I messed with JackRabbit once, and the pain was brought. Performance, concurrency and the API probably improved since then.<br /></li></ul>I would definintely try to avoid running multiple database versions at the same time. You can easily go from 1, 2 versions and then reach 100.<br /><br />What would you developers do in such a situation?Yves Zoundihttp://www.blogger.com/profile/08473720919389407655noreply@blogger.com1