Narkisrhttp://narkisr.comSome guy's blog about software related matters.Trippinghttp://narkisr.com/blog/2011/72ea33cd3240f7989f99227307000ee8http://narkisr.com/blog/2011/72ea33cd3240f7989f99227307000ee8Sat, 08 Oct 2011 00:01:27 -0400<p> Securing your Linux server takes the same Unix philosophy as other parts of the system, meaning you have an assortment of tools each does its own special thing and does it well.<br/> One of these tools is Tripwire an intrusion detection tool that safe guard the servers filesystem integrity, Tripwire creates a hash DB of a configurable files list, on each check tripwire report back on suspicious changes. <br/> In this post ill showcase how to set it up on your Ubuntu server, starting with installation, while some <a href="http://www.gerald.comuf.com/2011/03/how-to-install-tripwire-in-ubuntu/">posts</a> suggest installing from source id rather go with the pretty latest version in the repos: <pre name="code" class="brush: bash"> $ sudo aptitude install tripwire </pre> During the installation you will be asked for a site and local passphrase, <a href="http://manpages.ubuntu.com/manpages/natty/man1/pwgen.1.html">generate</a> some good passwords for those and get ready for configuration. <br/> </p> <p> Tripwire configuration consists of two main files, twcfg.txt and twpol.txt (both under /etc/tripwire), its suggested to encrypt and back them up after configuration is done (so that the bad guys won't know what folders your watching>?), the twpol (policy) file include which folders/files to watch for changes and the severeness level that such changes imply. <br/> Unfortunately the Ubuntu package generates a file that point to /proc, this is problematic since it contains files that represent process (those are bound to change), go ahead and apply the following in the policy file: <pre name="code" class="brush: bash"> # # Critical devices # ( rulename = "Devices & Kernel information", severity = $(SIG_HI), ) { /dev -> $(Device) ; /dev/mem -> $(Device) ; /dev/null -> $(Device) ; /dev/zero -> $(Device) ; /proc/devices -> $(Device) ; /proc/net -> $(Device) ; /proc/tty -> $(Device) ; /proc/sys -> $(Device) ; /proc/cpuinfo -> $(Device) ; /proc/modules -> $(Device) ; /proc/mounts -> $(Device) ; /proc/dma -> $(Device) ; /proc/filesystems -> $(Device) ; /proc/interrupts -> $(Device) ; /proc/ioports -> $(Device) ; /proc/kcore -> $(Device) ; /proc/self -> $(Device) ; /proc/kmsg -> $(Device) ; /proc/stat -> $(Device) ; /proc/loadavg -> $(Device) ; /proc/uptime -> $(Device) ; /proc/locks -> $(Device) ; /proc/version -> $(Device) ; /proc/meminfo -> $(Device) ; /proc/cmdline -> $(Device) ; /proc/misc -> $(Device) ; } </pre> Another spot I had to adjust is the /root part: <pre name="code" class="brush: bash"> # These files change the behavior of the root account ( rulename = "Root config files", severity = 100 ) { /root -> $(SEC_CRIT) ; # Catch all additions to /root /root/.bash_history -> $(SEC_CONFIG) ; /root/.bashrc -> $(SEC_CONFIG) ; /root/.profile -> $(SEC_CONFIG) ; } </pre> Now we are ready to apply our configuration changes: <pre name="code" class="brush: bash"> $ sudo twadmin --create-polfile --cfgfile /etc/tripwire/tw.cfg --site-keyfile /etc/tripwire/site.key /etc/tripwi re/twpol.txt </pre> Lets create our initial DB: <pre name="code" class="brush: bash"> $ sudo tripwire --init --cfgfile /etc/tripwire/tw.cfg --polfile /etc/tripwire/tw.pol --site-keyfile /etc/tripwire/site.key --local-keyfile /etc/tripwire/narkisr.com-local.key </pre> And run our first check: <pre name="code" class="brush: bash"> $ sudo tripwire --check # ... Rule Name Severity Level Added Removed Modified --------- -------------- ----- ------- -------- Invariant Directories 66 0 0 0 Tripwire Data Files 100 0 0 0 Other binaries 66 0 0 0 Tripwire Binaries 100 0 0 0 Other libraries 66 0 0 0 Root file-system executables 100 0 0 0 System boot changes 100 0 0 0 Root file-system libraries 100 0 0 0 (/lib) Critical system boot files 100 0 0 0 Other configuration files 66 0 0 0 (/etc) Boot Scripts 100 0 0 0 Security Control 66 0 0 0 Root config files 100 0 0 0 Devices & Kernel information 100 0 0 0 Total objects scanned: 12050 Total violations found: 0 </pre> The report list all the changes that were made to you system since the last check, lets play a bit: <pre name="code" class="brush: bash"> $ sudo touch /bin/bla $ sudo tripwire --check # ... ------------------------------------------------------------------------------- Rule Name: Root file-system executables (/bin) Severity Level: 100 ------------------------------------------------------------------------------- Added: "/bin/bla" Modified: "/bin" </pre> As you can see tripwire warns us about the new file, lets fix it up: <pre name="code" class="brush: bash"> $ sudo rm /bin/bla $ sudo tripwire --check #... /bin has still been changed ------------------------------------------------------------------------------- Rule Name: Root file-system executables (/bin) Severity Level: 100 ------------------------------------------------------------------------------- Added: "/bin/bla" Modified: "/bin" $ sudo tripwire --update -Z low --twrfile /var/lib/tripwire/report/narkisr.com-20111007-185529.twr # ... Remove the "x" from the adjacent box to prevent updating the database with the new values for this object. Modified: [x] "/bin" </pre> Tripwire marks changes with "[x]" giving us the options to accept changes that were made as legal, further checks will not warn us about them.<br/> The last thing left is to automate the reporting to that we can follow if things break on a regular basis: <pre name="code" class="brush: bash"> $ sudo cat /etc/cron.d/tripwire 0 2 * * * /usr/sbin/tripwire --check | /usr/bin/mail "narkisr@somewhere.com" -s "Tripwire Check" 2>&1 </pre> Ubuntu PXE-ing, not a walk in the parkhttp://narkisr.com/blog/2011/3503f63073b5263a911c92f384000b3fhttp://narkisr.com/blog/2011/3503f63073b5263a911c92f384000b3fFri, 30 Sep 2011 05:28:27 -0400<p> Ubuntu is one of the most user friendly systems both on the desktop side and on the server side, still there is one part in which Ubuntu requires a bit of tinkering which is pre-seeding automatic desktop installations.<br/> Most examples out there are targeted for server installations, in this post will explain how to setup a complete automatic installation for Ubuntu desktop (PXE boot with preseeding). <br/> Note that ill be using cobbler as the PXE server and apt-mirror but I won't be covering those in detail (there is enough material out there about these). </p> First a couple of perquisites: <ul> <li>Get Ubuntu <a href="http://www.ubuntu.com/download/ubuntu/alternative-download">alternate</a> cd, the plain desktop cd cannot be used in automatic installations.</li> <li>Install Cobbler on the server from which your going to serve your installations, following these <a href="https://help.ubuntu.com/community/Cobbler/Installation">instructions</a>.</li> <li>Setup apt-mirror, you can follow my <a href="http://narkisr.com/blog/2011/ab324c9d7dc60364c96dea66d8000349">guide</a>.</li> </ul> Now that we are all set will import the alternate cd into cobbler: <pre name="code" class="brush: bash"> $ sudo mount -o loop ubuntu-11.04-alternate-amd64.iso /media/loop $ sudo cobbler import --name=ubuntu-alternate --path=/media/loop --breed=ubuntu --os-version=natty </pre> Next we will add entries to our /etc/apt/mirror.list file, this is <a href="https://help.ubuntu.com/community/Installation/LocalNet#Advanced:_Network_install_using_apt-mirror">required</a> in order to enable our local mirror during the installation: <pre name="code" class="brush: bash"> deb http://host/mirrors/ubuntu natty main main/debian-installer restricted restricted/debian-installer </pre> Now comes the fun part, preseeding, iv found it to be a black art that involves a lot of trial and error, <a href="https://help.ubuntu.com/community/Cobbler/Preseed">feed</a> the following <a href="https://gist.github.com/1255305">preseed</a> file within cobbler, will go through the important options starting with using our local apt-mirror during installation: <pre name="code" class="brush: bash"> # Mirror settings # setting country string manual is crucial otherwise the mirror setting will not work! d-i mirror/country string manual d-i mirror/http/hostname string mirror-url d-i mirror/http/directory string /ubuntu d-i mirror/http/proxy string d-i mirror/udeb/components multiselect main, restricted </pre> Next is partitioning without Lvm which is a bit tricky: <pre name="code" class="brush: bash"> # partitioning d-i partman-auto/method string regular d-i partman-lvm/device_remove_lvm boolean true d-i partman-lvm/confirm boolean true d-i partman/confirm_write_new_label boolean true d-i partman/choose_partition select Finish partitioning and write changes to disk d-i partman/confirm boolean true d-i partman/confirm_nooverwrite boolean true d-i partman/default_filesystem string ext4 </pre> Now that we partitioned we can proceed to package selection, if we don't tell the installation to setup the Ubuntu desktop we will be left without any GUI, the following sets this up: <pre name="code" class="brush: bash"> tasksel tasksel/first multiselect ubuntu-desktop </pre> Specifying more packages is possible using: <pre name="code" class="brush: bash"> # Making it puppet ready d-i pkgsel/include string byobu vim openssh-server puppet </pre> You can now create a profile within cobbler that will be inherited by systems to be installed, make sure to set: <ul> <li>Mac address for systems (so that cobbler will connect the dots).</li> <li>The preseed file within the profile.</li> <li>The following kernel opts priority=critical locale=en_US (without this the preseed will be ignored).</li> </ul> All things should have been ready now for installation but unfortunately cobbler has the following <a href="https://bugs.launchpad.net/ubuntu/+source/cobbler/+bug/827496">bug</a>, cobbler creates the following /var/lib/tftpboot/pxelinux.cfg/MAC-ADDRESS file for each system: <pre name="code" class="brush: bash"> default linux prompt 0 timeout 1 label linux kernel /images/ubuntu-alternate-x86_64/linux ipappend 2 append initrd=/images/ubuntu-alternate-x86_64/initrd.gz locale= priority=critical locale=en_US text auto url=http://192.168.x.x/cblr/svc/op/ks/system/playing hostname= domain=local.lan suite=natty </pre> The last file within this file states the kernel options that will be used for the system, notice the empty hostname value, this value takes precedence on what ever value we set in the preseed file, making us a bit jammed. The only workaround is to somehow set this value right before the installation takes place, ill update this post if once ill reach the final solution but right now ill be using a simple web service to patch this file.<br/> Pin puppet freehttp://narkisr.com/blog/2011/4c122aba406ecb27152d034740000df2http://narkisr.com/blog/2011/4c122aba406ecb27152d034740000df2Sat, 04 Jun 2011 01:23:27 -0400<p>One of the best things I like about Linux (and Ubntnu in particular) is the package management, yet the main drawback of non rolling distros repositories is that you get might stuck with old package versions until the next release comes along.<br/> Usually you can find a PPA or a vendor package that gives you the new goodies, in the case of puppet your left with 2.6.4, while you could build puppet from source (its ruby after all) the integration with OS is lost.<br/> </p> After some frantic googling all iv found was <a href='http://tinyurl.com/3mle7qh'>this</a> which states the ability of using debian packages as the source for latest puppet version.<br/> Reading about apt pinning and the strong recommendation to use source packages instead lead me to the following solution: <pre name="code" class="brush: bash"> echo "deb-src http://ftp.us.debian.org/debian/ wheezy main" | sudo tee -a /etc/apt/sources.list sudo aptitude update cd /tmp/ sudo apt-get build-dep puppet sudo apt-get -b source puppet </pre> We add debian wheezy repository to our apt source.list and update, then we install the build dependencies of puppet and build puppet packages from source, we make sure to do all this in /tmp since the packages will be created under the cwd. <pre name="code" class="brush: bash"> $ ls /tmp puppet-2.6.8 puppet_2.6.8.orig.tar.gz puppetmaster-passenger_2.6.8-1_all.deb puppet_2.6.8-1_all.deb puppet-common_2.6.8-1_all.deb puppet-testsuite_2.6.8-1_all.deb puppet_2.6.8-1_amd64.changes puppet-el_2.6.8-1_all.deb vim-puppet_2.6.8-1_all.deb puppet_2.6.8-1.debian.tar.gz puppetmaster_2.6.8-1_all.deb puppet_2.6.8-1.dsc puppetmaster-common_2.6.8-1_all.deb </pre> Now in order to install puppetmaster: <pre name="code" class="brush: bash"> $ sudo dpkg -i puppetmaster-common_2.6.8-1_all.deb $ sudo dpkg -i puppetmaster_2.6.8-1_all.deb </pre> Installing puppet client: <pre name="code" class="brush: bash"> $ sudo dpkg -i puppet-common_2.6.8-1_all.deb $ sudo dpkg -i puppet_2.6.8-1_all.deb </pre> Its important to mention that this procedure might not work for other packages since Ubuntu and Debian are not binary compatible. P3wn Windows from Ubuntuhttp://narkisr.com/blog/2011/5004cdba31d7626c259c931a4d000ad8http://narkisr.com/blog/2011/5004cdba31d7626c259c931a4d000ad8Fri, 21 Jan 2011 00:34:00 -0500<p> I don't run windows, still there are cases that I need to remotely run a windows tool in an automated fashion, up till now I didn't find a working solution, psexec is the tool of choice on the windows platform, googeling will lead you to this forum <a href="http://ubuntuforums.org/showthread.php?p=9098595">post</a> that mentions winexe.<br/> Finding how to use the tool and installing the latest version (0.9.1) on Ubuntu 10.10 took me some time that I hope this post will spare.<br/> Most sites offer to compile winexe right from zenoss <a href='http://dev.zenoss.org/svn/trunk/wmi/Samba/source'>repo</a> going this route will lead you to 0.8 version running which didn't work with a remote win7, another (less mentioned) option is on sourceforge, the <a href="http://sourceforge.net/projects/winexe/">project page</a> offers 0.91 source tar, lets head on to business:<br/> <pre name="code" class="brush: bash"> $ wget http://tinyurl.com/4t8vjwl && tar -xvzf 4t8vjwl $ cd winexe-0.91/source4 $ ./autogen.sh $ ./configure $ make $ bin/winexe winexe version 0.91 This program may be freely redistributed under the terms of the GNU GPLv3 ... </pre> Using the tool is as follows: <pre name="code" class="brush: bash"> $ bin/winexe -U windows-domain/user%pass //machine-name "cmd" C:\ we are in windows land </pre> Note that the machine name is that under the windows domain and not dns name, the user must have admin remote priviliges in the domain (not just on the machine) in order to bypass that you can <a href='http://help.lockergnome.com/vista/access-administrative-share-enabling-admin-accoun--ftopict25338.html'>regedit</a> your way out, I wish you all a windows-less future :) apt-mirror, local speeduphttp://narkisr.com/blog/2011/ab324c9d7dc60364c96dea66d8000349http://narkisr.com/blog/2011/ab324c9d7dc60364c96dea66d8000349Sat, 08 Jan 2011 04:31:00 -0500One of the biggest advantages of Linux are package manager like apt yum and pacman, its really easy to get your software installed via a single command.<br/> Still installing package via your WAN can be time/bandwidth consuming, there are two main solutions: <ul> <li>Caching tools like <a href='https://help.ubuntu.com/community/Apt-Cacher-Server'>Apt-Cacher</a> that cache installed packages in a local proxy server, the main drawback is that the first one who installs a package waits the most.</li> <li>Mirroring tools like <a href='http://apt-mirror.sourceforge.net/'>apt-mirror</a> that mirror an entire repository onto a local server, the main drawback of mirroring is the initial sync operation bandwidth (can take 50Gb) and storage capacity.</li> </ul> <br/> Iv choose to use mirroring mainly because the time a single machine will have to wait the first time, lets start by installing apt-mirror: <pre name="code" class="brush: bash"> $ sudo aptitude install apt-mirror </pre> The main configuration file is /etc/apt/mirror.list: <pre name="code" class="brush: bash"> ############# config ################## set base_path /media/ubuntu-mirror set limit_rate 15k set mirror_path $base_path/mirror set skel_path $base_path/skel set var_path $base_path/var set nthreads 10 set _tilde 0 ############# end config ############## deb-i386 http://archive.ubuntu.com/ubuntu maverick main restricted universe multiverse deb-i386 http://archive.ubuntu.com/ubuntu maverick-security main restricted universe multiverse deb-i386 http://archive.ubuntu.com/ubuntu maverick-updates main restricted universe multiverse #deb-i386 http://archive.ubuntu.com/ubuntu maverick-proposed main restricted universe multiverse #deb-i386 http://archive.ubuntu.com/ubuntu maverick-backports main restricted universe multiverse deb-i386-src http://archive.ubuntu.com/ubuntu maverick main restricted universe multiverse deb-i386-src http://archive.ubuntu.com/ubuntu maverick-security main restricted universe multiverse deb-i386-src http://archive.ubuntu.com/ubuntu maverick-updates main restricted universe multiverse #deb-i386-src http://archive.ubuntu.com/ubuntu maverick-proposed main restricted universe multiverse #deb-i386-src http://archive.ubuntu.com/ubuntu maverick-backports main restricted universe multiverse deb-amd64 http://archive.ubuntu.com/ubuntu maverick main restricted universe multiverse deb-amd64 http://archive.ubuntu.com/ubuntu maverick-security main restricted universe multiverse deb-amd64 http://archive.ubuntu.com/ubuntu maverick-updates main restricted universe multiverse #deb-amd64 http://archive.ubuntu.com/ubuntu maverick-proposed main restricted universe multiverse #deb-amd64 http://archive.ubuntu.com/ubuntu maverick-backports main restricted universe multiverse deb-amd64-src http://archive.ubuntu.com/ubuntu maverick main restricted universe multiverse deb-amd64-src http://archive.ubuntu.com/ubuntu maverick-security main restricted universe multiverse deb-amd64-src http://archive.ubuntu.com/ubuntu maverick-updates main restricted universe multiverse #deb-i386-src http://archive.ubuntu.com/ubuntu maverick-proposed main restricted universe multiverse #deb-i386-src http://archive.ubuntu.com/ubuntu maverick-backports main restricted universe multiverse clean http://archive.ubuntu.com/ubuntu </pre> Notice limit_rate and nthreads, both will affect how much bandwidth will be used during sync, iv also disabled source downloads, we can now run the initial sync: <pre name="code" class="brush: bash"> $ apt-mirror Downloading 90 index files using 10 threads... </pre> The initial sync will take some time, feel free to stop it at any stage (it will resume once restarted), once its done will head on to set regular update job, edit /etc/cron.d/apt-mirror to the following: <pre name="code" class="brush: bash"> # # Regular cron jobs for the apt-mirror package # 0 4 * * * apt-mirror /usr/bin/apt-mirror >> /var/spool/apt-mirror/var/cron.log 2>&1 </pre> Unlike the default setting Im redirecting stderr and also appending to the log file, in order to serve apt requests from this server will use Nginx: <pre name="code" class="brush: bash"> $ cd /var/www $ sudo ln -s /media/ubuntu-mirror/mirror/archive.ubuntu.com/ubuntu ubuntu </pre> Last thing left is to edit /etc/apt/sources.list to use our new local mirror: <pre name="code" class="brush: bash"> #deb cdrom:[Ubuntu 10.10 _Maverick Meerkat_ - Release amd64 (20101007)]/ maverick main restricted # See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to # newer versions of the distribution. deb http://mirror-host/ubuntu/ maverick main restricted ## Major bug fix updates produced after the final release of the ## distribution. deb http://mirror-host/ubuntu/ maverick-updates main restricted ... </pre> apt-getting was never faster. Automation, automation, automation! [0..2]{automation}!http://narkisr.com/blog/2010/44ff8020070980da719d091cb98b3d1ehttp://narkisr.com/blog/2010/44ff8020070980da719d091cb98b3d1eFri, 20 Aug 2010 02:21:07 -0400<p> There are always tasks that look too small to worry about, copying a file pasting that line, the comforting sound of repetition.<br/> Uh? as devs we are better than that, we can program complex logic in commercial settings there is no reason not to apply our knowledge to every day tasks, let the machines do what they do best, repeat!<br/> For example the enjoyable task of copying the contents of cd's (remember those?) onto your hard drive, the drill is quite simple you pop in a cd, head on to the file manager gui select all files, enter copy and move into the destination folder, oh and don't forget to create a unique folder for each copied cd, now repeat that 50x times, can we do better?<br/> </p> <pre name="code" class="brush: ruby"> PREFIX = '/home/ronen/temp/' last_cd_in = lambda{ %x(dmesg | grep ISOFS).split("\n").last } def mounted_at res = nil res_ok = lambda{res && res.split(' ')[1]} 10.times { puts 'another attempt' res = `cat /proc/mounts | grep sr0`; break if res_ok.call sleep 1 } notify 'failed to find mount point' and exit 1 if !res_ok.call res.split(' ')[1].gsub('040',' ') end def notify (msg) `notify-send '#{msg}' -t 10` end def sh(cmd) res = `#{cmd}` notify("#{cmd} failed") and exit(1) if $?.to_i != 0 res end last = nil eject_action = lambda { sh 'eject' last = last_cd_in.call puts 'place the cd in, press enter when your done' gets } eject_action.call while(true) sh 'eject -t' begin curr = last_cd_in.call end while last==curr dest ="#{PREFIX}#{%x(uuid)}" sh "mkdir #{dest}" if !system("cp -rv #{mounted_at()}/* #{dest}") notify 'Failed to copy cd, please check media!' end eject_action.call end </pre> <p> This script enables the following functionality: <ul> <li>Cdrom tray is popped out and the user is prompted to enter a new one in.</li> <li>A unique destination folder is created (using uuid).</li> <li>The contents is copied to the destination.</li> <li>The cd is popped out ready for another round.</li> </ul> </p> <p> As for the implementation its Ruby mixed with good old unix tools like cp, mkdir eject and some /proc trickery to keep track of new mounted cd path, I find this combination a win win, we use Ruby instead of bash and use standard unix tools set instead of writing them ourself, Ruby has excellent unix process management API's (as any one who used Java for that can approve).<br/> Notify-send is a nice decor (Ubuntu notification system) that growls at us when things go wrong (keeping us free to roam into more interesting domains). </p> Another annoying task is waiting for tests to end in Intellij, this is not using our time, wouldn't it be great to be notified when tests fail? (not supported OOTB): <pre name="code" class="brush: ruby"> require 'rubygems' require 'open4' def numeric?(object) true if Float(object) rescue false end while (true) pid=`jps -v | grep AppMain | awk '{print $1}'` if numeric?(pid) puts "JUnit found at PID #{pid}" opid, stdin, stdout, stderr = Open4::popen4("strace -p #{pid}") Process::waitpid2 opid lines = stderr.readlines if lines.last.include? '255' `notify-send 'tests failed!' -u critical` else `notify-send 'all tests passed!' -u critical` end end sleep 2.5 end </pre> Same idea again, using Linux tool box with Ruby to automate our task, this script polls all Java processes for AppMain (Intellij main class runner), once found strace is attached to it in order to grab the exit code and notify-send the matching return status, the theme is repeating levrage the operating system and Ruby in order to turn a mundane task into an enjoyable one! Fasten your seatbelthttp://narkisr.com/blog/2010/4fc34088701d5d7f22b46536f791764chttp://narkisr.com/blog/2010/4fc34088701d5d7f22b46536f791764cSat, 03 Jul 2010 03:07:42 -0400<p> Using your IDE effeciently is an integral part of being a proficient developer, Intellij offers a multitude of options to turn your coding experience into a fast mouseless one.<br/> While most developers memorize the key bindings they tend to less explore other options of cutting key strokes away, in this post ill cover couple of those, while the examples ill be showing are in Java land the ideas should be useful in other languages as well.<br/> </p> How many times did you find yourself writing the following during a typical programming day? (at least I hope you did): <pre name="code" class="brush: java"> @Test public void someTest(){ // .. } </pre> <p> You type the public void someTest proceeded by the curely braces, then you head up and add the @Test annotation, quite repetative isn't it? it would be nicer to be able to do something like: </p> <pre name="code" class="brush: java"> test &lt;Tab&gt; expands to -> @Test public void &lt;cursor&gt;(){ } // now you enter the test name @Test public void someTest(){ } </pre> In order to enable this head on to the settings (using Alt+Ctrl+S) and search "Live Templates", add a new template called test with the following content: <pre name="code" class="brush: java"> @Test public void $NAME$ { } </pre> Make sure to set the context as Java Code and your set to go, other templates that I like are iter (foreach loop), psvm (public void main), and thru (throw runtime). <p> Another optimization helps us to find out early when we forget to implement an interface method: </p> <pre name="code" class="brush: java"> public interface Bar { void someMethod(); } public class Foo implements Bar { // a long list of other methods public void someMethod(){// oops // intellij default comment } // yet some more code } </pre> <p> Discovering it couple of minutes later during (hopfully) a test is quite annoying, wouldnt it be nice to get warned if you forgot to implement it? </p> <pre name="code" class="brush: java"> public class Foo implements Bar { // a long list of other methods public void someMethod(){ throw new RuntimeException("not implemented yet"); } // yet some more code } </pre> Head on to settings and look for "File Templates", select "implemented method body" and replace it with "throw new RuntimeException("not implemented yet");", this will make un-implemented methods fail loud and clear. <p> Our last optimization involves finals, mutating local variables and method parameters is limiting readability and make it harder to write thread safe code: </p> <pre name="code" class="brush: java"> public class NotReadable{ public void wacky(int i) { //.. post some logic with j i = j; // multiple lines after, do we really know what i is now? return i + 4; } } </pre> Making them final solves this however going past each one manualy is really tidiouse so most devs just avoid it, well there is an easy way to automate it, head on settings and search for inspections, look for "decleration can have final modifier" and enable it: <pre name="code" class="brush: java"> public class NotReadable{ public void wacky(int i) {// intellij highlights i, alt + enter and select "fix all" // ... } } </pre> In post iv introduced three quick methods of saving key strokes, our goal is not count how many keys we press but rather to remove distractions in order to concetrate better on the problem we are trying to solve.APT Bandwidth Diethttp://narkisr.com/blog/2010/9d908f588482cf0dd17e7c4b962f989fhttp://narkisr.com/blog/2010/9d908f588482cf0dd17e7c4b962f989fSat, 17 Apr 2010 01:57:27 -0400<p> In this post ill cover how to sync your Ubuntu installation without sacrificing a large amount of bandwidth, its commons to have a number of machines with the same packages installed the question is how we sync them all up (especially clean installs) without using up bandwidth.<br/> One could setup a proxy if the machines share the same local network however for distributed scenario's (multiple networks) this won't do.<br/> </p> A nice solution is apt-move (from the man page): <blockquote> apt-move - move cache of Debian packages into a mirror hierarchy. </blockquote> <p> apt-move enables us to create a mirror from our local apt cache, we can then distribute the mirror on a removable drive using an iso format, the target machines will add the iso image by using apt-cdrom to the sources list, using the local filesystem instead the web. </p> <p> The first thing is to make sure that apt-move won't delete any thing from the cache: </p> <pre name="code" class="brush: bash"> $ sudo aptitude install apt-move # within /etc/apt-move.conf make sure to set COPYONLY to yes => COPYONLY=yes </pre> Now lets create the mirror: <pre name="code" class="brush: bash"> # clearing old packages $ sudo aptitude autoclean # clearing the apt-move target $ sudo rm -rf /mirrors/debian # this dumps packages from /var/cache/apt/archives into /mirrors/debian $ sudo apt-move -d karmic update $ cd /mirrors/debian # this isn't created by apt-move, a possible bug? $ sudo mkdir -p dists/karmic/non-free/binary-i386 # this solves permission issues $ sudo chmod 777 . -R $ sudo apt-ftparchive packages pool/main/ | gzip -9c > dists/karmic/main/binary-i386/Packages.gz $ sudo apt-ftparchive packages pool/non-free/ | gzip -9c > dists/karmic/non-free/binary-i386/Packages.gz </pre> Take a look into /mirrors/debian/pool folder, youll be able to see all the packages that the mirror contains, note that packages which are not within the cache folder will be missing even if you installed them before (we will see later how to bypass this), lets create the ~/Release.dummy file (the mirror Release file): <pre name="code" class="brush: bash"> APT::FTPArchive::Release { Origin "APT-Move"; Label "APT-Move"; Suite "karmic"; Codename "karmic"; Architectures "i386"; Components "main restricted"; Description "Ubuntu Updates CD"; }; </pre> Place the Release file within the mirror folder: <pre name="code" class="brush: bash"> $ cd /mirrors/debian $ rm dists/karmic/Release $ apt-ftparchive -c ~/Release.dummy release dists/karmic/ > Release $ mv Release dists/karmic/ </pre> Now will need a gpg key in order to sign our Release file, in this stage we will also create the iso: <pre name="code" class="brush: bash"> $ gpg --gen-key $ gpg -bao dists/karmic/Release.gpg dists/karmic/Release # no need for this folder $ rm -rf .apt-move # creating the name of the iso $ mkdir .disk $ echo Ubuntu-Updates `date +%Y-%m-%d` > .disk/info # will need the public key within the iso $ gpg --export -a "Your Name" > public.key # creates the iso file $ mkisofs -r -A "Ubuntu Updates `date +%Y%m%d`" -o ~/ubuntu-updates.iso /mirrors/debian </pre> Now copy this iso to your favorit portable media in order to use it on the target machine: <pre name="code" class="brush: bash"> $ sudo mount -o loop /path/to/iso/ubuntu-updates.iso /cdrom $ sudo apt-key add /cdrom/public.key # during the issue of this command the /cdrom gets unmounted, mount -o loop again before pressing enter $ sudo apt-cdrom add -d=/cdrom # mount the iso again due to the last command </pre> We can now install packages from the iso, lets intall java (assuming you had it in you cache): <pre name="code" class="brush: bash"> $ sudo apt-get install sun-java6-jdk # the install should point to local filesystem & not the web (note from section). Selecting previously deselected package sun-java6-jre. (Reading database ... 146576 files and directories currently installed.) Unpacking sun-java6-jre (from .../sun-java6-jre_6-15-1_all.deb) ... sun-dlj-v1-1 license has already been accepted Selecting previously deselected package sun-java6-bin. Unpacking sun-java6-bin (from .../sun-java6-bin_6-15-1_i386.deb) ... sun-dlj-v1-1 license has already been accepted ... </pre> <p> In the case that you had a package that was cleared from the cache you can restore is by using: </p> <pre name="code" class="brush: bash"> # re-install with only download flag $ sudo apt-get install -d package-name --reinstall </pre> I hope that this will save you time post the near 10.04 release ;)Update Couchdb via FUSEhttp://narkisr.com/blog/2010/c20b6275f7e59f4d099ca4b2b55c0811http://narkisr.com/blog/2010/c20b6275f7e59f4d099ca4b2b55c0811Sat, 10 Apr 2010 01:48:49 -0400<p> FUSE is one of my favorite projects it really makes FS development accessible, it can abstract almost any resource as a file system making it first class citizen in the UNIX realm,<br/> an option that I was thinking about is to represent a Couchdb database as a folder. A possible use case might be a Dropbox/Ubuntu-one like clone (taking an advantage on Couchdb excellent replication) another one might be "greping" documents, the entire UNIX set will be able to process them. <br/> </p> <p> Apparently im not the first to think about this, enter <a href="http://code.google.com/p/couchdb-fuse/">Couchdb FUSE</a>, this project enables the manipulation of document attachments (files), the install process under Ubuntu is a bit undocumented, I had to figure it out myself: </p> <pre name="code" class="brush: bash"> $ sudo aptitude install libfuse2 fuse-utils# installing fuse $ sudo aptitude install python-setuptools # this installs easy_install $ sudo aptitude install python-dev libfuse-dev # fuse-python requires it $ sudo easy_install couchdb $ sudo easy_install couchdb-fuse $ sudo easy_install fuse-python </pre> <p> Now we should be able to mount a single document attachments like so: </p> <pre name="code" class="brush: bash"> $ mkdir couchmount $ curl -X PUT http://localhost:5984/fuse $ curl -X POST http://localhost:5984/fuse -H 'Content-Type: text/javascript; charset=utf-8' -d '{}' # an empty document, next step will use its id $ couchmount http://localhost:5984/fuse/6a53b4e951ea836b7fef55e7afafcd7a couchmount $ touch couchmout/bla $ curl -X GET http://localhost:5984/fuse/6a53b4e951ea836b7fef55e7afafcd7a {"_id":"6a53b4e951ea836b7fef55e7afafcd7a","_rev":"2-d9a4307289432688cd5a2f2d5c605f88","_attachments":{"bla":{"stub":true,"content_type":"","length":0,"revpos":2}}} </pre> This is all nice but lacks couple of features that id like to have: <ul> <li>Mounting an entire DB & exposing all the documents.</li> <li>Make the entire document editable (not just the attachments).</li> <li>Enable full CRUD access to the DB.</li> </ul> I guess that this calls for another solution, do you have any thing in mind?Artifactory meets VPShttp://narkisr.com/blog/2010/e71a88687bef0c9e4db04f8191272638http://narkisr.com/blog/2010/e71a88687bef0c9e4db04f8191272638Mon, 05 Apr 2010 05:28:27 -0400<p>If your using Maven/Gradle/Lein/Buildr to build your projects than you must have stumbled upon one common issue which is where to host your artifacts,<br/> syncing your local repository between machines is impossible without a proxy, a nice solution is to host it on a VPS.</br> I didn't find a single clear source of information on how to do so in a safe manner so ill try to cover the main points in this post.<br/> Before going further please take note to the following disclaimer: <b>Im not a security expert, any damage cause by following these steps is your responsibility.</b><br/> </p> <p> Lets start with the main components that we are going to use, first is Artifactory my favorite maven proxy that runs on an embedded jetty server out of the box, its common to place a reverse proxy in front of Java server in order to gain performance (mainly for static content) and enhanced security.<br/> Iv chosen to deploy Nginx as our proxy since its very lite on resources, offers good performance and has excellent documentation.<br/> </p> In order to forward traffic from Nginx to Artifactory will need to add the following section to nginx.conf: <pre name="code" class="brush: javascript"> server { server_name example.com; listen 80; location ~ ^/artifactory/(.*)$ { access_log /var/log/nginx_67_log; proxy_pass http://127.0.0.1:8081; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } </pre> <p> Now that we proxy the traffic from Nginx to Artifactory we need to start thinking on how to protect Artifactory from the outside world, one of the simplest forms of protecting online resources is using <a href="http://en.wikipedia.org/wiki/Basic_access_authentication">basic authentication</a>, in this configuration the user has to provide user name & password in order to access a url: </p> <pre name="code" class="brush: javascript"> server { server_name example.com; listen 80; location ~ ^/artifactory/(.*)$ { auth_basic "Restricted"; auth_basic_user_file /some/path/htpass; access_log /var/log/nginx_67_log; proxy_pass http://127.0.0.1:8081; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } </pre> <p> We added two new lines to the configuration, the htpass file is the file that contains the user details which are required for authentication, in order to generate this file: </p> <pre name="code" class="brush: bash"> $ sudo aptitude install apache2-utils $ pwgen -s 50 # make sure to use strong passwords! $ htpasswd -c htpass username </pre> <p> Now we should be set to access Artifactory using the credentials we created above, in order to enable maven to use these credentials we can set the following in the settings.xml file (on our client machine): </p> <pre name="code" class="brush: xml"> <settings xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd" xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <servers> <server> <id>Artifactory</id> <username>username</username> <password>password</password> <configuration> <authenticationInfo> <userName>username</userName> <password>password</password> </authenticationInfo> </configuration> </server> </servers> <mirrors> <mirror> <mirrorOf>*</mirrorOf> <name>repo</name> <url>http://example.com/artifactory/repo</url> <id>Artifactory</id> </mirror> </mirrors> </settings> </pre> <p> <b>Wait!</b>, while all this should work it is totally <b>insecure!</b><br/> Basic authentication is nothing more than a formalized method of sending user name and password out on the clear via http, its very easy to intercept.</br> We must make sure that the authentication info is send on an encrypted channel using ssl, in order to enable that we have to: </p> <ul> <li>Create a self signed certificate for our server (or buy one from a <a href="http://en.wikipedia.org/wiki/Certificate_authority">CA</a>). </li> <li>Configure Nginx to use the certificate and change the protocol to ssl on the Artifactory urls.</li> <li>Import the certificate to our client (Java or a browser in our case).</li> </ul> <p>Will start with the certificate creation, ill go ahead with the self signed one, this is quite the <a href="http://wiki.nginx.org/NginxHttpSslModule">standard</a> procedure with the only exception of using AES256 instead of DES3:</p> <pre name="code" class="brush: bash"> $ cd /usr/local/nginx/conf $ openssl genrsa -aes256 -out server.key 1024 # generating a private rsa key $ openssl req -new -key server.key -out server.csr # create a certificate based upon the key, when asked "Common Name (eg, YOUR name) []:" make sure to use your proper domain name! $ cp server.key server.key.org # see next $ openssl rsa -in server.key.org -out server.key # removing the pass phrase of the key $ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt # sign certificate with private key (clients use it). </pre> Now lets go ahead & make Nginx use ssl: <pre name="code" class="brush: javascript"> server { server_name example.com; listen 443; ssl on; ssl_certificate /usr/local/nginx/conf/server.crt; ssl_certificate_key /usr/local/nginx/conf/server.key; access_log /var/log/nginx/ssl.access.log; error_log /var/log/nginx/ssl.error.log; location ~ ^/artifactory/(.*)$ { auth_basic "Restricted"; auth_basic_user_file /some/path/htpass; access_log /var/log/nginx_67_log; proxy_pass http://127.0.0.1:8081; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_read_timeout 500; proxy_send_timeout 600; } } server { # making sure that the redirects that artifactory makes will remain under https listen 80; server_name example.com; location ~ ^/artifactory/(.*)$ { rewrite ^(.*) https://$server_name$1 permanent; } } </pre> <p> Now all that is left is to import the certificate to our clients, in the case of a browser just add an exception & import it, in the case of Java based tools like Maven we need to import the certificate using Java keytool: </p> <pre name="code" class="brush: bash"> sudo keytool -import -alias example.com -file /some/path/server.crt -keystore /usr/lib/jvm/java-6-sun/jre/lib/security/cacerts </pre> Note that since all Artifactory related traffic is now https so we need to adjust our settings file as well: <pre name="code" class="brush: xml"> <settings xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd" xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- rest unchanged--> <mirrors> <mirror> <mirrorOf>*</mirrorOf> <name>repo</name> <url>https://example.com/artifactory/repo</url> <id>Artifactory</id> </mirror> </mirrors> </settings> </pre> <p> Now that we feel secure & fuzzy all round there is still one issue to consider which is brute force attacks, nothing stops any one from pounding our server to death using tools like <a href="http://www.openwall.com/john/">John the Ripper</a>.<br/> </p> <p> A tool to fight such attacks is <a href="http://www.fail2ban.org/wiki/index.php/Main_Page">fail2ban</a>, this tool polls log files after patterns & triggers iptable drop instructions upon matches, lets go ahead & install it: </p> <pre name="code" class="brush: bash"> $ sudo aptitude install fail2ban $ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local </pre> Add the following defenition to the jail.local file: <pre name="code" class="brush: javascript"> [artifactory] enabled = true port = https filter = nginx-auth logpath = /var/log/nginx/ssl.error.log maxretry = 3 bantime = -1 </pre> Now lets add the filter to a new file under /etc/fail2ban/filter.d/nginx-auth.conf: <pre name="code" class="brush: javascript"> [Definition] failregex = no user/password.*client\: &lt;HOST&gt; user.*authentication failure.*client\: &lt;HOST&gt; user.*not found.*client\: &lt;HOST&gt; user.*password mismatch.*client\: &lt;HOST&gt; </pre> Thats a lot of configuration mayham, let me know if you found it useful!The world as a sequencehttp://narkisr.com/blog/2010/7479db8d6f121a623a3b4716d720ec14http://narkisr.com/blog/2010/7479db8d6f121a623a3b4716d720ec14Sat, 03 Apr 2010 04:34:40 -0400<p> Hey there! welcome to my new blog, after long time of blogsphere absence iv returned with a new self hosted blog that iv developed, this little project gave me a couple of insights that id like to share. </p> <p> One of the main abstractions that Clojure uses is that of a <a href="http://clojure.org/sequences">Sequence</a>, a seq is an interface (a java one) that represents a logical immutable persistent list, any data structure that expose this interface enables a vast number of core functions to our disposal.<br/> Nothing up to this point should sound out of the ordinary except that the real fun begins when we define our own sequences! </p> Lets take for example the entries of a Jar file, by using repeatedly on the archive input stream we get a seqence of entries to work with, this turns the stream into a first class Clojure citizen that we can doseq on, in this case to extract the entries in the unjar function: <pre name="code" class="brush: Clojure"> (defn- jar-stream-seq [stream] (take-while #(not= nil %) (repeatedly #(.getNextEntry stream)))) ; extract-entry emitted for brevity (defn unjar [src dest] (with-open [jar-stream (JarArchiveInputStream. (file-in-stream src))] (let [dir (file dest)] (doseq [entry (jar-stream-seq jar-stream)] (extract-entry entry dir jar-stream))))) </pre> <p> Another example is CouchDb to Clojure state syncronization, most applications that interacts with CouchDb (or any other persistent storage) hold some state that need to be updated in order to reflect lastest changes. <br/> Instead of polling the DB we can (in the case of CouchDb) listen to a broadcasted via a url (http://localhost:5984/db/_changes?feed=continuous&heartbeat=1000): </p> <pre name="code" class="brush: java"> {"seq":1,"id":"43badb35255a94b4ab5c3168553d1acc","changes":[{"rev":"2-8630b20788a2fd2618d85d2239a31f7f"}],"deleted":true} {"seq":2,"id":"1ed79fc5a1ddfaaf08a73e68b1f5432e","changes":[{"rev":"2-a72a134b273510eaa247c142fc62fd51"}],"deleted":true} {"seq":3,"id":"df76d2644cef31df9f9e4e6db29e614d","changes":[{"rev":"5-1bbc0c3f12cf3b3f23ef7f2fb99a6e8e"}]} </pre> This channel publishes all the changes in a json format that we can consume (can you guess already how?): <pre name="code" class="brush: Clojure"> (defn- bytes-seq [input] (take-while #(not= -1 %) (repeatedly #(. input read)))) (defn- changes-seq [] (let [url (URL. (couch str "/_changes?feed=continuous&heartbeat=1000&since=" (last-seq))) uc (. url openConnection)] (. uc connect) (filter (comp not blank?) (map #(reduce (fn [r c] (str r c)) "" %) (partition-by #(if (= \newline %) true) (map char (bytes-seq (. uc getInputStream)))))))) (defn follow-couch-changes [] (doseq [change (changes-seq) :let [id (read-id change)]] (when (not-design-id id) (dosync (alter posts-map assoc id (read-with-date id)) (alter posts init-posts))))) </pre> <p> The bytes-seq gives a bytes sequence that is mapped into chars and partitioned into lines under changes-seq, note that since we use heartbeat of 1000 millis (keeping the connection open) we get empty lines that are filtered out, the processing of these events is made using the standard Clojure functions.<br/> Another important aspect of this is that we can process <bold>infinite</bold> sequences (as in this case). </p> We can think of many parts of the outside world as a collection of sequences waiting to be processed by the same functional constructs that form the base of Clojure, Taking this approach we get an idiomatic Clojure code that really show how powerfull the language is. Cool Groovy techniqueshttp://narkisr.com/blog/2010/6070163998436828898http://narkisr.com/blog/2010/6070163998436828898Sat, 09 Jan 2010 06:13:00 -0500Groovy is a versatile & very powerful language to code with, as a Java super set it enables a Java programmer to write its code with all the known Java idioms & progress into Groovy land in small steps, in this post ill present two techniques that I find to be very powerful. <br/> <br/>The first is closure initialization, in Java land its common that when we have an object A which uses another object B with non trivial construction code (which depends on A's input) than we write all the initialization code of B inside A constructor: <br/> <pre name="code" class="brush: groovy"> class ComplexInit { // our B // ... some state that need to be initialized by users of this class } class UsesComplex {// our A private ComplexInit v def UsesComplex(){ v = new ComplexInit() //.. some complex initialization logic which depends on UsesComplex } }</pre> <br/>Another common practice is to create a factory that will encapsulate the initialization of ComplexInit class taking A as input: <br/> <pre name="code" class="brush: groovy"> class ComplexInitFactory { def createComplexWith(UsesComplex u){ // initialization code which depends on } }</pre> <br/>Groovy offers another way which I named "closure initialization":<br/> <div class='gray'> <pre name="code" class="brush: groovy"> class UsesComplex{ private ComplexInit val = { def result = new ComplexInit() // more logic here }() def UsesComplex(){ // ComplexInit is initialized above } }</pre> </div> <br/>Note that we are embedding a closure within the UsesComplex class & call it immediately after it has been defined, this resembles static initializer code blocks in Java except that it not static at all, the anonymous closure has access to its surrounding scope & can access other data members during its run: <br/> <pre name="code" class="brush: groovy"> class UsesComplex{ def today = new Date() private ComplexInit val = { def result = new ComplexInit() result.a = today result }() }</pre> <br/>By separating our constructors into initialization blocks we modularize the construction of our object, making our code more readable & DRY (no separation between deceleration & initialization). <br/>Another interesting technique is dynamic method dispatch, in Groovy we can dispatch methods like so:<br/> <pre name="code" class="brush: groovy"> class Target{ def methodA(){ println 'hey'} } new Target().methodA() new Target()."methodA"()// this works too!</pre> <br/>This means that we can dispatch methods according to run time logic:<br/> <pre name="code" class="brush: groovy"> class Target{ def calcA(){'a'} def calcB(){'b'} def calcC(){'c'} def notCalc(){'d'} } def t = new Target() def calcs = t.metaClass.methods.findAll{it.name.startsWith('calc')}.collect{it.name} calcs.each{println t."$it"()}// will print a b c</pre> <br/>Its true that Java reflection has similar capabilities however the Java API is very verbose & not as elegant, use this technique with care since it may result with hard to read code! <br/><br/>Thats about it for this post, let me know if you find these techniques useful in your code. Synching your enviroment aroundhttp://narkisr.com/blog/2009/1432286694230195736http://narkisr.com/blog/2009/1432286694230195736Sat, 31 Oct 2009 08:34:00 -0400Ubuntu 9.10 has just came out & iv rushed to upgrade, upgrading my 9.04 to 9.10 via the upgrade manager is a working option but usually id rather do a clean install & get a fresh system to poke around. <br/>The main issue that clean install brings is restoring your old environment which includes installed programs, settings files (.bashrc, .vimrc etc..), non packaged applications (usually the latest & greatest versions of Clojure, Groovy etc..). <br/>Another issue is the need to restore these settings on multiple machines while keeping it all consistent between them, there must a better way than working it all manually! <br/><br/>Well the solution that iv come with involve two tools, <a href="http://www.getdropbox.com/">Dropbox</a> & <a href="http://automateit.org/">AutomateIt</a>, Dropbox is no more than a fancy folder to the cloud synchronizer which enables me to access all my settings file from any machine, lsym-ing my .bashrc, .vimrc & any other file that id like to share across machines into the Dropbox folder is all that is required. <br/> <br/>The second part involves AutomateIt, which is a configuration management framework written in Ruby, an easy way of re-creating symlinks from my Dropbox folder onto a new system is using the following AutomateIt script: <br/> <pre name="code" class="brush: ruby"> HOME = ENV['HOME'] DROP = "#{HOME}/Private/Dropbox" def link(src,dst) ln_s("#{DROP}/#{src}","#{HOME}/#{dst}") end # Vim link "vim/.vimrc",".vimrc" link "vim/.vim",".vim" link "vim/.vimclojure-2.1.2",".vimclojure" # Bash link "BashEnv/.bashrc",".bashrc link "BashEnv/.inputrc", # Languages link "prog-langs/.clojure",".clojure" link "prog-langs/.groovy",".groovy" link "prog-langs/.jruby",".jruby" </pre> <br/>The nice thing about it is that it hides all the nitty gritty details that id have to figure out when using plain Ruby (or any other environment for that matter), AutomateIt wraps common tasks with a bash like DSL, unlike bash this DSL is portable across multiple unix systems & it hides many of the complexities that follow. <br/>AutomateIt performs actions only when they are required, this solves annoying cases that rise when scripts run more than once on a system (e.g. appending text to files). <br/> <br/>Another cool feature is package management, AutomateIt is capable of interacting with multiple packaging systems (yum, apt, gem etc..) in a transparent way, its easy to replicate installed packages onto multiple systems: <br/> <pre name="code" class="brush: ruby"> # bash %w(terminator rlwrap).each{ |p| package_manager.install p} # programming %w(vim git-core).each{ |p| package_manager.install p} # communication %w(deluge openssh-server).each{ |p| package_manager.install p} # misc %w(gpodder gnome-do).each{ |p| package_manager.install p} # installing dropbox download_manager.download 'http://www.getdropbox.com/download?dl=packages/nautilus-dropbox_0.6.1_i386_ubuntu_9.10.deb' , :to => '/tmp/nautilus-dropbox_0.6.1_i386_ubuntu_9.10.deb'<br/>package_manager.install ({'nautilus-dropbox' => '/tmp/nautilus-dropbox_0.6.1_i386_ubuntu_9.10.deb'} , :with => :dpkg) </pre> <br/>Using these tools has made configuration nirvana a bit closer to me & hopefully to you :) Dont overflow yourself!http://narkisr.com/blog/2009/8871420951859863603http://narkisr.com/blog/2009/8871420951859863603Fri, 24 Jul 2009 01:57:00 -0400Clojure has many nice less highlighted features, one of these is overflow protection, this can be a true life saver: <br/> <pre name="code" class="brush: clojure"> user=> (unchecked-add 1 2); not safe but might be faster 3 user=> (unchecked-add (. Integer MAX_VALUE) 2); oops -2147483647 user=> (+ (. Integer MAX_VALUE) 2) ; using safe arithmetic again 2147483649 user=> (+ (. Integer MAX_VALUE) 23) 2147483670 user=> (class (+ (. Integer MAX_VALUE) 23)); Clojure does the right thing for us java.lang.Long </pre> <br/><br/>It does pack more than just concurrency up its sleeve. Genericsfaction, getting some generics satisfactionhttp://narkisr.com/blog/2009/2938055409941179112http://narkisr.com/blog/2009/2938055409941179112Tue, 30 Jun 2009 00:26:00 -0400Java generics have a lot of short shortcoming, most of which are the result of the religious backward compatibility that Java is known for. <br/>One of the most annoying "features" of generics is type erasure in which the compiler removes (<a href="http://java.sun.com/javase/6/docs/api/java/lang/Class.html#getGenericSuperclass()">almost</a>) any trace of generic types meta data. <br/> <br/>Iv been pondering about this issue & had a simple idea, what if we could add back in the meta data that the erasing process removed? <br/>So, iv decided to create a proof of concept in order to show how this might work and named it <a href="http://github.com/narkisr/genericsfaction/tree/master">genericsfaction</a>.<br/> <br/>Using genericsfaction requires an additional code manipulation stage in which the source code is scanned & gets its AST manipulated (meta data is introduced), each manipulated source file is dumped into a separate folder (named gen), all that is left is to compile the files under gen (instead of the original src). <br/> <br/>At the moment there are only two enrichments implemented, the first is method input parameters annotation enrichment: <br/> <pre name="code" class="brush: java"> public void twoTypeParamsMet(@GenMeta(stringRep = "((Object ()) (Object ()))", classes = { Object.class, Object.class }) Map &lt;Object, Object&gt; map) { // method code }</pre> <br/><br/>The second is variable initialization enrichment:<br/> <pre name="code" class="brush: java"> public static void main(String [] args) { List&lt;Integer&gt; list = (List &lt;Integer&gt;)MetaProxy.newInstance(new ArrayList&lt;Integer&gt;(),"(Integer ())",new Class []{Integer.class}); }</pre> <br/>The reason that annotations aren't used in this case is due to this <a href="http://forums.sun.com/thread.jspa?threadID=664018">limitation</a>.<br/> <br/>There is no release to play with yet, however the source is up on github (mostly Clojure), I am planing on making a release as soon as ill finish to implement a validation module that uses this meta data in runtime. Newify your Objecthttp://narkisr.com/blog/2009/7964072952206948839http://narkisr.com/blog/2009/7964072952206948839Sat, 23 May 2009 11:21:00 -0400<span style="font-weight:bold;">Update</span> a generous Anonymous has left a comment that the following special macro form does the same as the newify function that i present later on: <br/> <pre name="code" class="brush: clojure"> (def nested-object (-> GrandFather. Father. GrandSon.)) </pre> <br/>Feel free to skip this entry (unless your interested in an alternative implementation).<br/> <br/>Instantiating large nested object graphs can be tedious in any language Clojure included:<br/> <pre name="code" class="brush: clojure"> (def nested-object (new Grandson (new Father (new Grandfather)))) </pre> <br/>All those new methods call get old pretty quickly and are not DRY, to remedy this will take advantage on a cool property of Clojure <a href="http://en.wikipedia.org/wiki/Homoiconicity">Homoiconicity</a>. <br/>Homoiconicity basically means that the code is represented by a basic data structure of the language itself (lists in the case of Clojure), this means that manipulating the AST is easy as pie! <br/>It would be nice if we could write something like the following:<br/> <pre name="code" class="brush: clojure"> (def nested-object (newify '(Grandson (Father (Grandfather))))) </pre> <br/>The newify function takes a nested list of objects & adds new before each object, post that the function evaluates the resulting list: <br/> <pre name="code" class="brush: clojure"> (defn newify [e] (eval (newify-imp e))) ; required since used before defined (defn- newify-rest [e] ) (defn- newify-imp [e] (let [add-new (partial cons 'new) add-rest (partial cons (first e))] (if (not (empty? e)) (-> (newify-rest e) add-rest add-new) e))) (defn- newify-rest [e] (map #(if (list? %) (newify-impl %) %) (rest e))) </pre> <br/>The newify-imp & newify-rest functions are mutually recursive, newify-imp adds the new symbol & the first list element to the result of the newify-rest function result, the newify-rest maps each list in the rest of the list to its newified value. <br/><br/>This implementation could be transformed into a recursive macro that will spare us from the list escaping: <br/> <pre name="code" class="brush: clojure"> (def nested-object (newify '(Grandson (Father (Grandfather))))) ; no escaping here (def nested-object (newify (Grandson (Father (Grandfather))))) </pre> <br/>Ill have to dig that option later on. NILFS on Jauntyhttp://narkisr.com/blog/2009/4967482019043022834http://narkisr.com/blog/2009/4967482019043022834Fri, 01 May 2009 01:56:00 -0400The latest release of Ubuntu includes the long awaited Ext4 FS (works flawlessly on my system). <br/>Ext4 is faster & more secure but still lacks the ability to manage FS snapshots (ZFS excels in that, but runs only in <a href="http://www.wizy.org/wiki/ZFS_on_FUSE">FUSE</a> on linux).<br/>An interesting alternative is <a href="http://www.nilfs.org/en/">NILFS</a>:<br/> <blockquote>NILFS is a log-structured file system supporting versioning of the entire file system and continuous snapshotting which allows users to even restore files mistakenly overwritten or destroyed just a few seconds ago. </blockquote><br/> <br/>NILFS maintains a repo for Hardy, the Jaunty repos contain only the user land tools which won't do us much good since we need the kernel module as well, this leaves us only with the option of installing it from source (still quite easy). <br/><br/> <pre name="code" class="brush: bash"> # a perquisite $ sudo aptitude install uuid-dev # installing kernel module, result module resides in /lib/modules/2.6.28-11-generic/kernel/fs/nilfs2/nilfs2.ko $ wget http://www.nilfs.org/download/nilfs-2.0.12.tar.bz2 $ tar jxf nilfs-2.0.12.tar.bz2 $ cd nilfs-2.0.12 $ make $ sudo make install # installing user land tools $ wget http://www.nilfs.org/download/nilfs-utils-2.0.11.tar.bz2 $ tar jxf nilfs-utils-2.0.11.tar.bz2 $ cd nilfs-utils-2.0.11 $ ./configure $ make $ sudo make install </pre> <br/>Creating a file system on a file (ideal for playing around):<br/> <pre name="code" class="brush: bash"> $ dd if=/dev/zero of=mynilfs bs=512M count=1 $ mkfs.nilfs2 mynilfs </pre> <br/>The FS is only a mount away:<br/> <pre name="code" class="brush: bash"> # mounting the file as a loop device $ sudo losetup /dev/loop0 mynilfs $ sudo mkdir /media/nilfs $ sudo mount -t nilfs2 /dev/loop0 /media/nilfs/ </pre> <br/>Now lets create a couple of files:<br/> <pre name="code" class="brush: bash">$ cd /media/nilfs $ touch 1 2 3 # listing all checkpoints & snapshots, on your system list should vary $ lscp CNO DATE TIME MODE FLG NBLKINC ICNT 7 2009-05-01 01:08:09 ss - 12 6 13 2009-05-01 19:05:34 cp i 8 3 14 2009-05-01 19:05:59 cp i 8 3 15 2009-05-01 19:07:09 cp - 12 6 # creating a snapshot $ sudo mkcp -s # 15 is the new snapshot (mode is ss) $ lscp CNO DATE TIME MODE FLG NBLKINC ICNT 7 2009-05-01 01:08:09 ss - 12 6 13 2009-05-01 19:05:34 cp i 8 3 14 2009-05-01 19:05:59 cp i 8 3 15 2009-05-01 19:07:09 ss - 12 6 16 2009-05-01 19:08:59 cp i 8 6 # our post snapshot file $ touch 4 </pre> <br/>Now lets go back in time into our snapshot, NILFS enables us to mount old snapshots as read only FS (while the original FS is still mounted): <br/> <pre name="code" class="brush: bash"> $ sudo mkdir /media/nilfs-snapshot $ sudo mount.nilfs2 -r /dev/loop0 /media/nilfs-snapshot/ -o cp=15 # only snapshots works! $ cd /media/nilfs-snapshot # as we might expect $ ls 1 2 3 </pre> <br/>NILFS has some interesting features, its not production ready yet however it sure worth looking after its development. MetaClasses can bite!http://narkisr.com/blog/2009/6534405333058201794http://narkisr.com/blog/2009/6534405333058201794Fri, 06 Mar 2009 05:30:00 -0500Groovy has MOP classes built in like the MetaClass class, this class enables (among other things) objects introspection, we could for example use its getProperties() method in order to get the list of all the meta properties of an object and copy their values into another object: <br/> <pre name="code" class="brush: groovy"> class ParentModel { def String parentProp /** * Copying the current object properties into the other object */ def copyInto(other){ this.metaClass.getProperties().findAll{it.getSetter()!=null}.each{metaProp-> if(metaProp.getProperty(this)!=null){ metaProp.setProperty(other,metaProp.getProperty(this)) } } other } }</pre> <br/>The usage is quite simple:<br/> <pre name="code" class="brush: groovy"> def parent = new ParentModel(parentProp:"parent") def copiedParent = parent.copyInto(new ParentModel()) assert copiedParent.parentProp.equals(parent.parentProp) </pre> <br/>While this code runs perfectly fine with object that have identical classes it has some unexpected side effects when one of the classes derives from another: <br/> <pre name="code" class="brush: groovy"> class DerivingModel extends ParentModel{ def derivedProp } def parent = new ParentModel(parentProp:"parent") def derived = new DerivingModel(derivedProp:"derived") def copiedDerived = parent.copyInto(derived) assert copiedDerived.parentProp.equals(parent.parentProp) assert copiedDerived.derivedProp.equals("derived")// throws groovy.lang.MissingPropertyException: // No such property: derived </pre> <br/>How can this be? the DerivingModel class has the derivedProp but after the copyInto invocation its missing! <br/>Lets see what the getProperties method actually returns:<br/> <pre name="code" class="brush: groovy"> def parent = new ParentModel(parentProp:"parent") parent.metaClass.getProperties().each{println it.name}// prints: class, parentProp, metaClass </pre> <br/>It seems that we don't only get the parentProp that we defined but also the metaClass and class properties, this means that in the derived case the copyInto method has set the metaClass and class values of ParentModel into the DerivedModel instance (causing it to lose access to its derivedProp). <br/>The fix is quite simple:<br/> <pre name="code" class="brush: groovy"> class ParentModel { def String parentProp def excludes = ['metaClass'] def copyInto(other){ this.metaClass.getProperties().findAll{it.getSetter()!=null}.each{metaProp-> // we must not set the metaClass of the current object into the other if(metaProp.getProperty(this)!=null && !excludes.contains(metaProp.name)){ metaProp.setProperty(other,metaProp.getProperty(this)) } } other } } </pre> <br/>There is no need to exclude the class property since it keeps the original even if set. Clojure on youtubehttp://narkisr.com/blog/2009/3394723648911558089http://narkisr.com/blog/2009/3394723648911558089Mon, 02 Mar 2009 00:41:00 -0500Iv really enjoyed watching the Intro to Clojure series:<br /><br /><object width="480" height="295"><param name="movie" value="http://www.youtube.com/v/Aoeav_T1ARU&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/Aoeav_T1ARU&hl=en&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="295"></embed></object><br /><br />If your interested what the fuss is about check it out!<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3915544030735587425-3394723648911558089?l=javadevelopmentforthemasses.blogspot.com' alt='' /></div>GroovyShell bindings validationhttp://narkisr.com/blog/2009/4670422564275710773http://narkisr.com/blog/2009/4670422564275710773Sat, 28 Feb 2009 09:24:00 -0500Groovy 1.6 got released not long a go with a <a href='http://www.infoq.com/articles/groovy-1-6'>load of new features</a>, one of these is AST transformations which basically lets developers manipulate/access Groovy's AST before it gets loaded into the JVM. <br/>This feature enables some really cool MOP options to mind however iv decided to try it in solving a non MOP-ish issue. <br/> <br/>The <a href='http://groovy.codehaus.org/api/groovy/lang/GroovyShell.html'>GroovyShell</a> is a very versatile and useful tool that enables us to evaluate any Groovy script file at runtime: <pre name="code" class="brush: groovy"><br/>def bindings = [lastDay:2] def script = """ import java.util.Calendar Calendar cal = Calendar.instance cal.set(2009,Calendar.FEBRUARY,2) def ghday = cal.time cal.set(2009,Calendar.MARCH,lastDay) def spring = cal.time def days = (ghday..spring).size() println days """ def shell = new GroovyShell(new Binding(bindings)) shell.evaluate(script)</pre> <br/>The script get its input parameters from the bindings hash, forgeting to pass an input variable (lastDay in this case) will cause a groovy.lang.MissingPropertyException to be thrown. <br/> <br/>This is quite reasonable during development time but not in other scenarios in which the script is written in one machine & evaluated on a remote machine. <br/>The exception gets thrown only post its evaluation which might be too late (deep in the execution flow), wouldn't it be nice if it was possible to validate this at will on the client side? <br/> <br/>We could scan the script for suspect variables that might not have been initialised, such scanning might be possible by inspecting the script AST, looking after variables that weren't declared in the current script, Groovy code visitors to the rescue! <br/><br/>The following implementation matches the bill perfectly: <pre name="code" class="brush: groovy"> package com.jdftm.script.valid import org.codehaus.groovy.ast.ClassCodeVisitorSupport import org.codehaus.groovy.ast.expr.MethodCallExpression import org.codehaus.groovy.control.SourceUnit import org.codehaus.groovy.ast.expr.VariableExpression import org.codehaus.groovy.ast.expr.DeclarationExpression class ClassCodeVisitorSupportImp extends ClassCodeVisitorSupport { def declared = [] def existsByDefault=['context','args'] def bindings def notInBindings = {name -> bindings?.keySet().find{it.equals(name)} == null} def notDeclared = {name -> declared?.find{it.text.equals(name)} == null && !existsByDefault.contains(name)} def notValid = {notDeclared(it.text) && !it.hasInitialExpression() && notInBindings(it.text)} def suspectVariables = [] public void visitMethodCallExpression(MethodCallExpression methodCall) { def variables=methodCall.arguments.expressions.findAll{(it instanceof VariableExpression)} suspectVariables } public void visitDeclarationExpression(final DeclarationExpression decleration){ declared } protected SourceUnit getSourceUnit() { return null; } }</pre> <br/>This visitor keeps a suspects list of all the variables that are either not in the declared variables or in the bindings hash. <br/>The following class encapsulates the visitor usage: <div class='gray'> <pre name="code" class="brush: groovy"> package com.jdftm.script.valid import org.codehaus.groovy.ast.ClassCodeVisitorSupport import org.codehaus.groovy.ast.ModuleNode import org.codehaus.groovy.control.SourceUnit import org.codehaus.groovy.control.CompilationUnit import org.codehaus.groovy.ast.ClassNode import org.codehaus.groovy.control.Phases; class GroovyScriptValidator { def validate(script,bindings){ def ast=getAST(script) def impl=new ClassCodeVisitorSupportImp() impl.bindings=bindings impl.visitClass((ClassNode)ast.getClasses().get(0)); impl.suspectVariables.flatten() } def ModuleNode getAST(String source) { SourceUnit unit = SourceUnit.create("Test",source); CompilationUnit compUnit = new CompilationUnit(); compUnit.addSource(unit); compUnit.compile(Phases.SEMANTIC_ANALYSIS); return unit.getAST(); } }</pre> </div><br/>Validating the script is now simple: <pre name="code" class="brush: groovy"> package com.jdftm.script.valid /** * * @author ronen */ class InParamValidationTest { public static void main(String[] args) { def bindings = [lastDay:2] def script = """ import java.util.Calendar Calendar cal = Calendar.instance cal.set(2009,Calendar.FEBRUARY,2) def ghday = cal.time cal.set(2009,Calendar.MARCH,lastDay) def spring = cal.time def days = (ghday..spring).size() println days """ def validator = new GroovyScriptValidator() def suspects = validator.validate(script,bindings) suspects.each{println it.text} if(suspects.size()==0){ def shell = new GroovyShell(new Binding(bindings)) shell.evaluate(script) } } }</pre> <br/>AST introspection is one cool feature to have! Demystifying Spring wiring processhttp://narkisr.com/blog/2009/3342994813256842539http://narkisr.com/blog/2009/3342994813256842539Sat, 17 Jan 2009 07:52:00 -0500Many Java applications these days make use of Spring IoC, taking the initialization management from the hand of the developer has many benefits but also has a couple of down sides like the lose of some control on the wiring process itself. <br/> <br/>Most of the time its a none issue however there are times in which Spring fails to resolve a dependency and all that the developer is left with is a cryptic stack trace to follow. <br/> <br/>Iv been thinking on how to make it possible to track down Spring weaving process and see at each stage what has been wired up, basically there are three approaches that iv considered: <br/> <ul><br/> <li>The first is to hook into the injection process by some public API, iv decided to drop it since i didn't find any API which notifies me upon beans creation and wiring. </li> <br/> <li>The second was to wire some Aspect into Spring injection process, iv started to read Spring source code and saw that pin point all the spots in code in which the wiring takes place is very tedious and error prone to start with. </li> <br/> <li>The third option was to think on Spring as an isolated container that has to interact with the JVM in order to create and inject objects into each other, tracing this interaction sholud give us the log of the injection process itself! </li> <br/></ul> <br/>A little more digging (see org.springframework.beans.BeanUtils) revealed that Spring uses Java reflection API (java.lang.reflect.Constructor.newInstance, java.lang.reflect.Field.set) in order to build/wire beans, armed with this knowledge we are only left to devise a method for tracing the calls to these methods. <br/> <br/>A possible option is Btrace, Btrace is a Java agent modeled after DTrace which is capable of instrumenting running Java classes, using the following Btrace script would activate the tracing of the wiring process on all the classes under the com.jdftm package: <br/> <pre name="code" class="brush: java"> package jdftm; import com.sun.btrace.annotations.*; import com.sun.btrace.AnyType; import static com.sun.btrace.BTraceUtils.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Field; @BTrace public class ReflecTracer { @OnMethod( clazz="/java.lang.reflect.Constructor/", method="/newInstance/") public static void anyNewInstance(Constructor con,Object[] args) { if(con!=null && matches("public\\scom\\.jdftm(\\.|\\w*)*\\(\\)",str(con))){ println(strcat(strcat("Object ",str(con))," got constructed")); } } @OnMethod( clazz="/java.lang.reflect.Field/", method="/set/") public static void anyFieldSet(Field field,Object obj,Object value) { println(strcat("Set invoked on ",str(field))); } }</pre> <br/><br/>Using the script with Btrace involve two steps, compilation:<br/> <pre name="code" class="brush: bash">btracec ReflecTracer.java</pre> <br/><br/>Agent attaching (attach before context creation, debugging is an option):<br/> <pre name="code" class="brush: bash">btrace &lt;process id, use jps&gt; jdftm/ReflecTracer.class</pre> <br/><br/>The following beans wiring:<br/> <pre name="code" class="brush: java"> public class BeanA { @Autowired private BeanB b; } public class BeanB { @Autowired private BeanA a; }</pre> <br/><br/>Produces the following traces:<br/> <pre name="code" class="brush: bash"> Object public com.jdftm.spring.context.BeanA() got constructed Object public com.jdftm.spring.context.BeanB() got constructed Set invoked on private com.jdftm.spring.context.BeanA com.jdftm.spring.context.BeanB.a Set invoked on private com.jdftm.spring.context.BeanB com.jdftm.spring.context.BeanA.b </pre> <br/>An interesting idea that i had is to create a graph out of these traces and give the developer even better visualization on the process. Learning some Haskellhttp://narkisr.com/blog/2009/3694637936001299074http://narkisr.com/blog/2009/3694637936001299074Sat, 10 Jan 2009 11:19:00 -0500Well iv been studying a little Haskell lately, mainly by reading <a href="http://learnyouahaskell.com/chapters">Learn You a Haskell for Great Good!</a>, I can only recommend any one to follow this book, my next read will be <a href="http://book.realworldhaskell.org/read/">Real world Haskell</a>.<br />Functional programing rulz!<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3915544030735587425-3694637936001299074?l=javadevelopmentforthemasses.blogspot.com' alt='' /></div>Pure Java entertainmenthttp://narkisr.com/blog/2008/4421559656072331256http://narkisr.com/blog/2008/4421559656072331256Fri, 26 Dec 2008 00:08:00 -0500Iv really enjoyed this <a href="http://www.youtube.com/watch?v=wDN_EYUvUq0">presentation</a> about Java puzzlers.<br />The main moral of this presentation in my mind is that we should relay more on static tools in order to avoid such corner cases (there is no way to remember them all).<br />Take a look im sure that youl enjoy it as I did.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3915544030735587425-4421559656072331256?l=javadevelopmentforthemasses.blogspot.com' alt='' /></div>VMware recovery methodshttp://narkisr.com/blog/2008/169674624870285444http://narkisr.com/blog/2008/169674624870285444Thu, 18 Dec 2008 10:46:00 -0500Iv been using VMware server and player for a time now and usually the hosted OS is XP, it happens to be that iv had the "luck" to witness the crash/corruption of such images and have devised two nifty tricks/methods of data recovery that i think worth sharing.<br />The first is for data recovery for an unbootable image, it matches cases in which you don't seem to be able to boot XP up but the image itself is readable & loaded by VMware (you see the black screen loading), the basic idea is to change the first boot device of the image to a Linux live cd (Ubuntu works perfectly), after booting up all you need to do is to mount the NTFS folder and copy it out (by scp, thumb drive, etc..).<br />The second one is more complex and comes to handle a case in which the image dose not load at all (vmware complains about a corrupted vmx file), in order to recover from this state there are a couple of prequisits:<ul><br /><li>VMware server installed.</li><br /><li>You have another working XP image with a vmx file.</li><br /><li>The corrupted image has a snapshot of a working state</li><br /></ul><br />The solution in this case is to copy the working vmx file into the folder of the corrupted image, load this image in VMware server and replace all the hard drive entries with the corrupted machine images, now all that is done is to revert to the last saved snapshot and see how the system is restored!<br />I hope that these two little methods help you as much as they helped me.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3915544030735587425-169674624870285444?l=javadevelopmentforthemasses.blogspot.com' alt='' /></div>Java statefull callbackshttp://narkisr.com/blog/2008/3275673969337735455http://narkisr.com/blog/2008/3275673969337735455Tue, 16 Dec 2008 11:32:00 -0500Any programmer comes to know callbacks at some point or another, in Java it looks something like this:<br/> <pre name="code" class="brush: java"> public interface Callback { void doCall(); } public class CallbackCosumer { public void execute(final Callback callback){ callback.doCall(); } } // usage public class Main { public static void main(String[] args) { final CallbackConsumer consumer = new CallbackConsumer(); consumer.execute(new Callback() { public void doCall() { System.out.println("doing my callback thingy"); } }); } }</pre> <br/>The biggest downside is that its hard to pass calling context state into the rigid callback interface, we could try something like: <br/> <pre name="code" class="brush: java"> public class CustomCallback &lt;T&gt; implements Callback { private &lt;T&gt; state; public void doCall() { System.out.println(state); } public void setState(&lt;T&gt; state) { this.state = state; } }</pre> <br/>Note that this implementation is limiting, the doCall method has to work for any type T, custom behavior will require sub classing (not reasonable expectation from the callback provider). <br/>A somewhat better (the most elegant that iv found to date) solution is to take advantage of another interface:<br/> <pre name="code" class="brush: java"> public interface StatefullCallback&lt;T&gt; extends Callback{ void addState(T state); } // Now we have a custom state object public static class CustomState { // fields .. } // And usage with a type matching logic public static void main(String[] args) { final CallbackConsumer consumer = new CallbackConsumer(); final StatefullCallback&lt;CustomState&gt; callback = new StatefullCallback&lt;CustomState&gt;() { private CustomState state; public void addState(final CustomState state) { this.state = state; } public void doCall() { // some custom logic that uses the custom state object } }; callback.addState(new CustomState()); consumer.execute(callback); }</pre> <br/>Its quite easy to see how its possible to pass multiple types of state objects into the callback execution context and do it with relative ease, closure-blessed languages require no such hacking.