<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9098580853969350531</id><updated>2011-11-28T17:20:52.344+08:00</updated><category term='linux'/><category term='apache'/><category term='mail'/><category term='google analytics'/><category term='iphone'/><category term='mysql'/><category term='groovy'/><category term='drupal'/><category term='postfix'/><category term='ubuntu'/><category term='kvm'/><category term='mongodb'/><category term='vm-builder'/><category term='port-forwarding'/><category term='database'/><title type='text'>Insert Something Creative</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>97</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4085596556432491730</id><published>2011-11-28T15:42:00.002+08:00</published><updated>2011-11-28T17:20:52.386+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vm-builder'/><category scheme='http://www.blogger.com/atom/ns#' term='kvm'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Setting up KVM on Ubuntu 10.04 (Lucid Lynx)</title><content type='html'>After doing a KVM install on Debian Squeeze and trying to get a VM up and running, the hassle convinced me to go back to Ubuntu and their vm-builder package, which allow ones to create VMs relatively easy once the setup is complete. There is a vm-builder port for Debian, though that only works for building older versions of Ubuntu and I want to run the latest, Ubuntu 11.10 (Oneiric Ocelot).&lt;br /&gt;&lt;br /&gt;Starting with a bare-metal Ubuntu 10.04 LTS (Lucid Lynx) 64-bit, below is the list of commands and instructions to install and set up the KVM. Details on these instructions can be read in the Ubuntu community documentation, &lt;a href="https://help.ubuntu.com/community/KVM/Installation"&gt;KVM Installation&lt;/a&gt; and &lt;a href="https://help.ubuntu.com/community/KVM/Networking"&gt;KVM Networking&lt;/a&gt;:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;virsh -c qemu:///system list&lt;/code&gt; (To verify installation, should have no errors)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo apt-get install libcap2-bin&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo setcap cap_net_admin=ei /usr/bin/qemu-system-x86_64&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo vi /etc/network/interfaces&lt;/code&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;b&gt;Original file:&lt;/b&gt;&lt;br /&gt;# The loopback network interface&lt;br /&gt;auto lo&lt;br /&gt;iface lo inet loopback&lt;br /&gt;&lt;br /&gt;# The primary network interface&lt;br /&gt;auto eth0&lt;br /&gt;iface eth0 inet static&lt;br /&gt;       address 10.10.3.140&lt;br /&gt;       broadcast 10.10.3.143&lt;br /&gt;       netmask   255.255.255.248&lt;br /&gt;       gateway   10.10.3.137&lt;br /&gt;&lt;br /&gt;# default route to access subnet&lt;br /&gt;up route add -net 10.10.3.136 netmask 255.255.255.248 gw 10.10.3.137 eth0&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;&lt;b&gt;Modified file:&lt;/b&gt;&lt;br /&gt;# The loopback network interface&lt;br /&gt;auto lo&lt;br /&gt;iface lo inet loopback&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;# device: eth0&lt;br /&gt;auto  eth0&lt;br /&gt;iface eth0 inet manual&lt;br /&gt;&lt;br /&gt;# The primary network interface&lt;br /&gt;auto br0&lt;br /&gt;iface br0 inet static&lt;br /&gt;       address 10.10.3.140&lt;br /&gt;       broadcast 10.10.3.143&lt;br /&gt;       netmask   255.255.255.248&lt;br /&gt;       gateway   10.10.3.137&lt;br /&gt;       bridge_ports eth0&lt;br /&gt;       bridge_stp off&lt;br /&gt;       bridge_fd 9&lt;br /&gt;       bridge_hello 2&lt;br /&gt;       bridge_maxage 12&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;# default route to access subnet&lt;br /&gt;up route add -net 10.10.3.136 netmask 255.255.255.248 gw 10.10.3.137 eth0&lt;br /&gt;&lt;b&gt;&lt;i&gt;up route add -net 10.10.3.136 netmask 255.255.255.248 gw 10.10.3.137 br0&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo /etc/init.d/networking restart&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Running &lt;code&gt;ifconfig&lt;/code&gt; lists the following interfaces &lt;code&gt;br0, eth0, lo, virbr0&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;This completes the KVM installation and creation of a bridge for the VMs. Up next is replacement of the vm-builder. The one in the Ubuntu packages is faulty and also will not allow you to install Ubuntu 11.10 (Oneiric Ocelot). So I updated to the latest, downloading the source, building and installing it. The steps below can be found in this &lt;a href="http://askubuntu.com/questions/73706/using-vmbuilder-to-build-an-11-10-vm-from-10-04"&gt;accepted answer&lt;/a&gt;:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo apt-get install bzr&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo apt-get install epydoc&lt;/code&gt; (big install here, ~400mb)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;bzr branch lp:ubuntu/vm-builder ubzr-vm-builder&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;cd ubzr-vm-builder&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;fakeroot debian/rules binary&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo dpkg -i ../*vm-builder*.deb&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;With that, everything is installed and vm-builder is ready to run. The easiest way is to use a script so that vm creation can be set once and repeated as desired. The only changes required being hostname, ip and maybe memory. Obtain the Ubuntu 11.10 64-bit server iso and put it in the same place as the script. The directory I used is ~/vm/basekvm:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;cd ~/vm/basekvm&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo vi create_vm.sh&lt;/code&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;b&gt;File:&lt;/b&gt;&lt;br /&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;# Configure this before running the command&lt;br /&gt;HOSTNAME=myhostname&lt;br /&gt;MEMORY=2048&lt;br /&gt;IP=192.168.122.10&lt;br /&gt;# -- End of configuration&lt;br /&gt;&lt;br /&gt;vmbuilder kvm ubuntu \&lt;br /&gt;--destdir=/var/lib/libvirt/images/$HOSTNAME \&lt;br /&gt;--ip=$IP \&lt;br /&gt;--hostname=$HOSTNAME \&lt;br /&gt;--mem=$MEMORY \&lt;br /&gt;--suite=oneiric \&lt;br /&gt;--flavour=virtual \&lt;br /&gt;--arch=amd64 \&lt;br /&gt;--iso=/root/vm/basekvm/ubuntu-11.10-server-amd64.iso \&lt;br /&gt;--mirror=http://de.archive.ubuntu.com/ubuntu \&lt;br /&gt;--libvirt=qemu:///system \&lt;br /&gt;--domain=localdomain \&lt;br /&gt;--part=/root/vm/basekvm/vmbuilder.partition \&lt;br /&gt;--bridge=virbr0 \&lt;br /&gt;--gw=192.168.122.1 \&lt;br /&gt;--mask=255.255.255.0 \&lt;br /&gt;--user=myusername \&lt;br /&gt;--name=myname \&lt;br /&gt;--pass=mypassword \&lt;br /&gt;--tmpfs=- \&lt;br /&gt;--addpkg=vim-nox \&lt;br /&gt;--addpkg=acpid \&lt;br /&gt;--addpkg=unattended-upgrades \&lt;br /&gt;--addpkg=openssh-server \&lt;br /&gt;--firstboot=/root/vm/basekvm/fboot.sh \&lt;br /&gt;-o&lt;br /&gt;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo chmod 700 create_vm.sh&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo vi fboot.sh&lt;/code&gt; (Optional)&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;b&gt;File:&lt;/b&gt;&lt;br /&gt;# This script will run the first time the virtual machine boots&lt;br /&gt;# It is ran as root.&lt;br /&gt;&lt;br /&gt;# Expire the user account&lt;br /&gt;passwd -e administrator&lt;br /&gt;&lt;br /&gt;# Install openssh-server&lt;br /&gt;apt-get update&lt;br /&gt;apt-get install -qqy --force-yes openssh-server&lt;br /&gt;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo chmod 777 fboot.sh&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo vi vmbuilder.partition&lt;/code&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;b&gt;File:&lt;/b&gt;&lt;br /&gt;root 8000&lt;br /&gt;swap 4000&lt;br /&gt;---&lt;br /&gt;/var 8000&lt;br /&gt;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;cd ~/vm&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;ln -s /var/lib/libvirt/images/ images&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;The create_vm.sh is basically a template script. You can modify it to accept console input so that you don't need to go and edit the file values, that is left for another time. The symbolic link shows the directory where the VM disk images are located once created. Below is how you would use it to create a VM:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo cp basekvm/create_vm.sh create_vm_myvmname.sh&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo vi create_vm_myvmname.sh&lt;/code&gt;. Edit the HOSTNAME, IP and MEMORY as desired&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;sudo ./create_vm_myvmname.sh&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;virsh start myvmname&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;And that's it! A VM has been successfully created and started up. Give it a few minutes and then you can log in through &lt;code&gt;ssh&lt;/code&gt; using the information in the script. If the ssh is slow to connect, try &lt;a href="http://www.turnkeylinux.org/blog/slow-ssh"&gt;this&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4085596556432491730?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4085596556432491730/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4085596556432491730' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4085596556432491730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4085596556432491730'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2011/11/setting-up-kvm-on-ubuntu-1004-lucid.html' title='Setting up KVM on Ubuntu 10.04 (Lucid Lynx)'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-625177343421210642</id><published>2011-11-25T22:35:00.004+08:00</published><updated>2011-11-25T23:58:36.618+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='port-forwarding'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='kvm'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>KVM host with gateway guest using port-forwarding</title><content type='html'>Using the 3 rules listed &lt;a href="http://serverfault.com/questions/170079/forwarding-ports-to-guests-in-libvirt-kvm"&gt;here&lt;/a&gt; and below, a KVM host can forward all http and ssh traffic to a specified gateway guest VM:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1:80&lt;br /&gt;iptables -t nat -I PREROUTING -p tcp --dport 22 -j DNAT --to-destination 10.0.0.2:22&lt;br /&gt;iptables -I FORWARD -m state -d 10.0.0.0/24 --state NEW,RELATED,ESTABLISHED -j ACCEPT&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;To make it permanent, requires one to go through this &lt;a href="https://help.ubuntu.com/community/IptablesHowTo"&gt;page&lt;/a&gt; and use the following commands:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;sudo sh -c "iptables-save -c &gt; /etc/iptables.rules" (after applying the 3 commands above)&lt;br /&gt;sudo vi /etc/network/if-pre-up.d/iptablesload&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;The &lt;code&gt;/etc/network/if-pre-up.d/iptablesload&lt;/code&gt; file will have the following text:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;iptables-restore &lt; /etc/iptables.rules&lt;br /&gt;exit 0&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;The KVM host will now have VM creation as its sole focus. Ensure the host's ssh port have been changed to make it accessible from outside, otherwise it can be accessed from the gateway guest.&lt;br /&gt;&lt;br /&gt;All redirection and VM access are transferred to the the gateway guest. The guest will need to install nginx so it can act as a http proxy for other VMs. All ssh access use the gateway guest as a stepping stone to the other VMs.&lt;br /&gt;&lt;br /&gt;Following the 3 rules, it is found the traffic essentially loops back to the gateway guest. This makes it incapable of reaching the other VMs. Applying 1 more rule after the 3 above solves this. The rule accepts all packets from the VM ip range and does not do any forwarding:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;iptables -t nat -I PREROUTING -p tcp --source 10.0.0.0/24 -j ACCEPT&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-625177343421210642?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/625177343421210642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=625177343421210642' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/625177343421210642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/625177343421210642'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2011/11/kvm-host-with-gateway-guest-using-port.html' title='KVM host with gateway guest using port-forwarding'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6333963875778653426</id><published>2011-02-07T09:54:00.003+08:00</published><updated>2011-02-07T13:11:05.807+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>A Certain Minimal QR Scanner iPhone app</title><content type='html'>A &lt;a href="http://en.wikipedia.org/wiki/QR_Code"&gt;QR Code&lt;/a&gt; is similar to a barcode, except it contains more information and looks like a pixellated square Rorschach test.&lt;br /&gt;&lt;br /&gt;There are a number of free QR readers in the appstore like &lt;a href="http://itunes.apple.com/us/app/neoreader/id284973754?mt=8"&gt;NeoReader&lt;/a&gt; and &lt;a href="http://itunes.apple.com/gb/app/redlaser/id312720263?mt=8"&gt;RedLaser&lt;/a&gt;. I especially like the scanning GUI for RedLaser, which seems more streamlined than any of the apps I have tried.&lt;br /&gt;&lt;br /&gt;A number of these apps use the open-source &lt;a href="http://code.google.com/p/zxing/"&gt;ZXing  ("Zebra Crossing")&lt;/a&gt; scanner library. The library is in Java but has a number of ports which include iPhone.&lt;br /&gt;&lt;br /&gt;To start things off, you need to download or checkout the source. Create a new "View-Based Application" project in Xcode. Inside the &lt;code&gt;iphone&lt;/code&gt; folder of the source, follow the &lt;code&gt;README&lt;/code&gt; on how to include the &lt;code&gt;ZXingWidget&lt;/code&gt; project into yours.&lt;br /&gt;&lt;br /&gt;Pay attention to the instructions, especially the direct dependency, header search path and the fact the file with the ZXing has to be a &lt;code&gt;.mm&lt;/code&gt; instead of &lt;code&gt;.m&lt;/code&gt;. If it does not build, you're probably missing something. You can look at the sample projects to see how they include the widget.&lt;br /&gt;&lt;br /&gt;One last thing before moving on to the code, put the &lt;code&gt;beep-beep.aiff&lt;/code&gt; file from the ScanTest project into your project. This is to get audio confirmation of a scan.&lt;br /&gt;&lt;br /&gt;Inside the sole &lt;code&gt;viewController&lt;/code&gt; of your project:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#import "ZXingWidgetController.h"&lt;br /&gt;#import "QRCodeReader.h"&lt;br /&gt;#import "ResultParser.h"&lt;br /&gt;#import "URLResultParser.h"&lt;br /&gt;#import "ResultAction.h"&lt;br /&gt;&lt;br /&gt;- (void)viewDidLoad {&lt;br /&gt;    [super viewDidLoad];&lt;br /&gt;    [ResultParser registerResultParserClass:[URLResultParser class]]; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (void)viewDidAppear:(BOOL)animated {&lt;br /&gt;    [super viewDidAppear:animated];&lt;br /&gt;    ZXingWidgetController *widController =&lt;br /&gt;  [[ZXingWidgetController alloc] initWithDelegate:self showCancel:NO OneDMode:NO];&lt;br /&gt;    QRCodeReader *qrcodeReader = [[QRCodeReader alloc] init];&lt;br /&gt;    NSSet *readers = [[NSSet alloc] initWithObjects:qrcodeReader,nil];&lt;br /&gt;    [qrcodeReader release];&lt;br /&gt;    widController.readers = readers;&lt;br /&gt;    [readers release];&lt;br /&gt;    NSBundle *mainBundle = [NSBundle mainBundle];&lt;br /&gt;    widController.soundToPlay =&lt;br /&gt; [NSURL fileURLWithPath:[mainBundle pathForResource:@"beep-beep" ofType:@"aiff"] isDirectory:NO];&lt;br /&gt;    [self presentModalViewController:widController animated:YES];&lt;br /&gt;    [widController release];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#pragma mark -&lt;br /&gt;#pragma mark ZXingDelegateMethods&lt;br /&gt;- (void)zxingController:(ZXingWidgetController*)controller didScanResult:(NSString *)resultString {&lt;br /&gt;    [self dismissModalViewControllerAnimated:YES];&lt;br /&gt;    ParsedResult *parsedResult = [[ResultParser parsedResultForString:resultString] retain];&lt;br /&gt;    NSArray *actions = [[parsedResult actions] retain];&lt;br /&gt; &lt;br /&gt;    if ([actions count] == 1) {&lt;br /&gt;        ResultAction *theAction = [actions objectAtIndex:0];&lt;br /&gt;        [theAction performActionWithController:self shouldConfirm:YES]; &lt;br /&gt;    } else {&lt;br /&gt;        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Text Found:"&lt;br /&gt;            message:resultString&lt;br /&gt;            delegate:nil&lt;br /&gt;            cancelButtonTitle:@"OK"&lt;br /&gt;            otherButtonTitles:nil];&lt;br /&gt;        [alertView show];&lt;br /&gt;        [alertView release];&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The code in &lt;code&gt;viewWillAppear&lt;/code&gt; is lifted off from the sample projects. This sets up the scanning video camera with the appropriate reader. If a scan is successful, the delegate method &lt;code&gt;didScanResult&lt;/code&gt; will execute. The result is parsed to see if it is a URL. You set which parser to use in &lt;code&gt;viewDidLoad&lt;/code&gt;. A parsed result can have default actions associated with it, the &lt;code&gt;URLResultParser&lt;/code&gt; opens up the url in Safari as default. Otherwise the result is treated as text and displayed.&lt;br /&gt;&lt;br /&gt;This app can now scan QR codes and open up URLs in Safari. There are a number of other things you can add to this, eg you can switch out the &lt;code&gt;ResultParser&lt;/code&gt; with a &lt;code&gt;UniversalResultParser&lt;/code&gt; that includes all the parser classes. You should take a look in the &lt;code&gt;Classes&lt;/code&gt; folder of the &lt;code&gt;ZXingWidget&lt;/code&gt; project to see what is available.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6333963875778653426?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6333963875778653426/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6333963875778653426' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6333963875778653426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6333963875778653426'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2011/02/certain-minimal-qr-scanner-iphone-app.html' title='A Certain Minimal QR Scanner iPhone app'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8217852101488855696</id><published>2010-04-07T12:12:00.003+08:00</published><updated>2010-04-07T15:44:50.906+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='mail'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='postfix'/><title type='text'>Setting up mail for your Ubuntu server</title><content type='html'>Need your bare-bones Ubuntu server to send out email notification and the like? Well, first you need to check what your hostname is and modify accordingly:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;hostname -f&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So my server's hostname is &lt;code&gt;microdude&lt;/code&gt;, you might also get it as &lt;code&gt;microdude.localdomain&lt;/code&gt;. You'll want to convert it into an FQDN (Fully Qualified Domain Name). That means I need to change my &lt;code&gt;microdude&lt;/code&gt; to &lt;code&gt;microdude.favoritemedium.com&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo vi /etc/hostname&lt;br /&gt;sudo vi /etc/hosts&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The output of hosts:&lt;br /&gt;&lt;code&gt;127.0.0.1 localhost&lt;br /&gt;127.0.1.1 microdude.localdomain microdude&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Would now be:&lt;br /&gt;&lt;code&gt;127.0.0.1 localhost&lt;br /&gt;127.0.1.1 microdude.favoritemedium.com microdude&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Reboot and check that the hostname has been changed to &lt;code&gt;microdude.favoritemedium.com&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo reboot&lt;br /&gt;hostname -f&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;After that, you're supposed to set up RDNS (Reverse Domain Name System), this helps avoid your mails falling prey to the all-powerful spam filter. You can check on this RDNS with &lt;code&gt;dig&lt;/code&gt; which can be installed from this package:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo apt-get install dnsutils&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This is optional, though if your mails start going into the spam folder, you'd best revisit this in the links provided.&lt;br /&gt;&lt;br /&gt;Now to install the actual mail agent onto the server with a &lt;a href="https://help.ubuntu.com/community/Tasksel"&gt;one-liner operation&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo tasksel install mail-server&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The process stops at two points for user input. The first is to pick the postfix configuration for the server, select the default &lt;code&gt;Internet site&lt;/code&gt;. The second is to set the main domain name, this should be already be filled with &lt;code&gt;microdude.favoritemedium.com&lt;/code&gt; and all you need to do is accept. &lt;br /&gt;&lt;br /&gt;Once finished, the postfix daemon should be running now. You need to know about two files, the main configuration file and the mail log. You don't need to mess around with the config file, since that should be set up correctly. The mail log is useful to check on whether mails have been sent or other information. Their locations:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;/etc/postfix/main.cf&lt;br /&gt;/var/log/mail.log&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now you'll want to test whether mails can be sent out. An email can be typed out in the terminal using the &lt;code&gt;mail&lt;/code&gt; command:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;mail testing@mailaddress.com&lt;br /&gt;Subject: Do not panic, this is a test&lt;br /&gt;Panic panic panic panic panic&lt;br /&gt;.&lt;br /&gt;Cc:&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Check the email account you sent the mail to and you should see that it is present.&lt;br /&gt;&lt;br /&gt;Congratulations, you can now spam to your heart's content =^_^=.&lt;br /&gt;&lt;br /&gt;From:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://articles.slicehost.com/email"&gt;http://articles.slicehost.com/email&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://articles.slicehost.com/2008/7/28/email-preparing-the-slice"&gt;http://articles.slicehost.com/2008/7/28/email-preparing-the-slice&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://articles.slicehost.com/2008/7/29/postfix-installation"&gt;http://articles.slicehost.com/2008/7/29/postfix-installation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://articles.slicehost.com/2010/3/1/barebones-postfix-install-for-ubuntu"&gt;http://articles.slicehost.com/2010/3/1/barebones-postfix-install-for-ubuntu&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8217852101488855696?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8217852101488855696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8217852101488855696' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8217852101488855696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8217852101488855696'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2010/04/setting-up-mail-for-your-ubuntu-server.html' title='Setting up mail for your Ubuntu server'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7277255903400851798</id><published>2010-04-06T18:32:00.004+08:00</published><updated>2010-04-06T19:25:18.028+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='drupal'/><category scheme='http://www.blogger.com/atom/ns#' term='apache'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Moving Drupal from one host to another</title><content type='html'>You've got a Drupal site running and now want to move it to another server which is bare-bones. This server is luckily running Ubuntu, which makes installing the rest of the LAMP (Linux, Apache, MySQL and PHP) stack a &lt;a href="https://help.ubuntu.com/community/Tasksel"&gt;one-line operation&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo tasksel install lamp-server&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The install process will stop at one point to ask for the password of the root user for MySQL. Once the install completes, use the MySQL command-line client to add in the same database (an empty one) and user that Drupal uses.&lt;br /&gt;&lt;br /&gt;Use &lt;code&gt;mysqldump&lt;/code&gt; to dump out the Drupal database data into an sql file. Load it in the new database, populating it. You'll want to tar up the whole directory where the Drupal files reside (not forgetting the .htaccess) and expand it out in the same location within the new machine. You may (not) need to edit &lt;code&gt;sites/default/settings.php&lt;/code&gt; or &lt;code&gt;.htaccess&lt;/code&gt; for any host information changes. &lt;code&gt;settings.php&lt;/code&gt; is also where you edit the database login information, if you decide to use different ones.&lt;br /&gt;&lt;br /&gt;With Apache running, you should be able to hit the new Drupal site. It looks to be running but there are a few gotchas. If you are (most likely) running Clean URLs, the links don't work anymore. You'll need to disable it to get navigation working at &lt;code&gt;http://hostname/?q=admin/settings/clean-urls&lt;/code&gt;, maybe going through &lt;code&gt;http://hostname/?q=user&lt;/code&gt; to log in first. To set up Clean URLs again, you need to run this line:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo a2enmod rewrite&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And edit &lt;code&gt;/etc/apache2/sites-available/default&lt;/code&gt;, changing the &lt;code&gt;AllowOverride None&lt;/code&gt; to &lt;code&gt;AllowOverride All&lt;/code&gt; inside the directory with the path &lt;code&gt;/var/www&lt;/code&gt;, or where the Drupal files live. Restart the server and you find that you can enable Clean URLs now.&lt;br /&gt;&lt;br /&gt;The other gotcha is that the status report is complaining it can't find the PHP GD library. Apparently PHP library is installed but not configured so you run these lines:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo apt-get install php5&lt;/code&gt; (optional?)&lt;br /&gt;&lt;code&gt;sudo apt-get install php5-gd&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Lastly, cron needs to be set up to update the Drupal site. I use &lt;code&gt;curl&lt;/code&gt; so the lines are:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo apt-get install curl&lt;/code&gt;&lt;br /&gt;&lt;code&gt;crontab -e&lt;/code&gt;&lt;br /&gt;&lt;code&gt;0 * * * * curl --silent --compressed http://localhost/cron.php&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The last line is done inside the &lt;code&gt;vi&lt;/code&gt; editor so after that, save and quit.&lt;br /&gt;&lt;br /&gt;Congratulations! Your Drupal site is now running fine on the new machine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7277255903400851798?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7277255903400851798/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7277255903400851798' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7277255903400851798'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7277255903400851798'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2010/04/moving-drupal-from-one-host-to-another.html' title='Moving Drupal from one host to another'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8847119807495971401</id><published>2010-03-30T09:31:00.005+08:00</published><updated>2010-03-30T10:32:39.828+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='google analytics'/><title type='text'>Google Analytics not showing Firefox and Internet Explorer hits, only Safari and Chrome</title><content type='html'>If you find your Google Analytics is not showing any results for Firefox and Internet Explorer and everything is correct with no problems on the Javascript side, you might want to take a closer look at the GA code. It might be that all the code is in one script block like so:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt; &lt;br /&gt;var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");&lt;br /&gt;document.write(unescape('%3Cscript src="'+gaJsHost+'google-analytics.com/ga.js" type="text/javascript"%3E%3C/script%3E'));&lt;br /&gt;&lt;br /&gt;try {&lt;br /&gt;    var pageTracker = _gat._getTracker('UA-XXXXXXX-X');&lt;br /&gt;    pageTracker._trackPageview();&lt;br /&gt;}&lt;br /&gt;catch (err) {}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The code that GA gives you to use is no mistake, you need to separate them out into two blocks:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt; &lt;br /&gt;var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");&lt;br /&gt;document.write(unescape('%3Cscript src="'+gaJsHost+'google-analytics.com/ga.js" type="text/javascript"%3E%3C/script%3E'));&lt;br /&gt;&lt;b&gt;&amp;lt;/script&amp;gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;/b&gt;&lt;br /&gt;try {&lt;br /&gt;    var pageTracker = _gat._getTracker('UA-XXXXXXX-X');&lt;br /&gt;    pageTracker._trackPageview();&lt;br /&gt;}&lt;br /&gt;catch (err) {}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The first code block is responsible for downloading the ga.js. That file needs to be loaded up before the second code block can execute properly. If they are in the same block, the try code will fail and no exception or alert is given.&lt;br /&gt;&lt;br /&gt;Below are three separate posts covering the same question:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.google.com/support/forum/p/Google%20Analytics/thread?tid=593d9d95f199f377&amp;hl=en"&gt;GA not tracking Mozilla or Firefox. Only shows Chrome and safari Clicks&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.google.com/support/forum/p/Google+Analytics/thread?tid=101c3fd523b5f3ce&amp;hl=en"&gt;Reports not showing some browsers&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.google.com/support/forum/p/Google+Analytics/thread?tid=78c72cd9be0ff84b&amp;hl=en"&gt;Analytics not showing visitors using Internet Explorer&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.roirevolution.com/blog/2009/04/6-tools-you-can-use-to-troubleshoot-google-analytics-yourself.html#comment-41498"&gt;last comment here&lt;/a&gt; lets you know what to look for in troubleshooting Google Analytics. The GA cookies are named __utma, __utmb, __utmc, __utmz, and __utmv and if you do not have any of them, GA is not working.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8847119807495971401?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8847119807495971401/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8847119807495971401' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8847119807495971401'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8847119807495971401'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2010/03/google-analytics-not-showing-firefox.html' title='Google Analytics not showing Firefox and Internet Explorer hits, only Safari and Chrome'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4191767920319494198</id><published>2009-08-04T16:28:00.002+08:00</published><updated>2009-08-04T17:06:22.784+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mongodb'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy Tutorial for MongoDB</title><content type='html'>Java Tutorial (http://www.mongodb.org/display/DOCS/Java+Tutorial)&lt;br /&gt;&lt;br /&gt;Since Groovy is based on Java, you can make use of the Java driver for MongoDB as well as go through the tutorial shown above. The code can be used as-is or modified to look more groovy.&lt;br /&gt;&lt;br /&gt;Create a groovy file (mongo.groovy) and place the Java driver in the same directory. Edit it so the code looks like:&lt;br /&gt;&lt;br /&gt;this.class.classLoader.rootLoader.addURL(new File("mongo-0.6.jar").toURL())&lt;br /&gt;&lt;br /&gt;import com.mongodb.*&lt;br /&gt;&lt;br /&gt;DBAddress address = new DBAddress("localhost", "mydb")&lt;br /&gt;Mongo db = new Mongo(address)&lt;br /&gt;db.authenticate('testUser', 'testPassword')&lt;br /&gt;&lt;br /&gt;DBCollection coll = db.getCollection("testCollection")&lt;br /&gt;&lt;br /&gt;BasicDBObject doc = new BasicDBObject()&lt;br /&gt;doc.put("name", "MongoDB")&lt;br /&gt;doc.put("type", "database")&lt;br /&gt;doc.put("count", 1)&lt;br /&gt;&lt;br /&gt;BasicDBObject info = new BasicDBObject()&lt;br /&gt;info.put("x", 203)&lt;br /&gt;info.put("y", 102)&lt;br /&gt;doc.put("info", info)&lt;br /&gt;&lt;br /&gt;coll.insert(doc)&lt;br /&gt;&lt;br /&gt;for(i in 1..100) {&lt;br /&gt;    coll.insert(new BasicDBObject().append("i", i))&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;println coll.getCount()&lt;br /&gt;&lt;br /&gt;DBCursor cursor = coll.find()&lt;br /&gt;while(cursor.hasNext()) {&lt;br /&gt;    println cursor.next()&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;You can see it's just a rehash of part of the Java tutorial, the output will be a count of the number of inserted objects followed by the objects themselves.&lt;br /&gt;&lt;br /&gt;The first line of code loads the jar file, this is useful if you're not looking to put the jar in a classpath or one of groovy's configured library paths like '~/.groovy/lib'.&lt;br /&gt;&lt;br /&gt;Running the script is accomplished by 'groovy mongo.groovy' in the terminal. You can also type in 'groovyConsole' to load the console then opening the script and running inside it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4191767920319494198?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4191767920319494198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4191767920319494198' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4191767920319494198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4191767920319494198'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2009/08/groovy-tutorial-for-mongodb.html' title='Groovy Tutorial for MongoDB'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7903063970537375052</id><published>2009-08-04T11:22:00.000+08:00</published><updated>2009-08-04T11:52:06.860+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mongodb'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Installing MongoDB on Ubuntu 9.04 Jaunty Jackalope</title><content type='html'>For the installation, I decided to build MongoDB (http://www.mongodb.org/) from source. The documentation regarding this is thorough and getting it running was a cinch. A Javascript engine called Spider Monkey is used and you need to build it with UTF8 support.&lt;br /&gt;&lt;br /&gt;The documents referred to:&lt;br /&gt;http://www.mongodb.org/display/DOCS/Building&lt;br /&gt;http://www.mongodb.org/display/DOCS/Building+Spider+Monkey&lt;br /&gt;http://www.mongodb.org/display/DOCS/Building+for+Linux&lt;br /&gt;&lt;br /&gt;The all-in-one command line version:&lt;br /&gt;Dependencies:&lt;br /&gt;    sudo apt-get install curl tcsh git-core scons g++&lt;br /&gt;    sudo apt-get install libpcre++-dev libboost-dev libmozjs-dev&lt;br /&gt;&lt;br /&gt;Spider Monkey installation:&lt;br /&gt;    curl -O ftp://ftp.mozilla.org/pub/mozilla.org/js/js-1.7.0.tar.gz&lt;br /&gt;    tar zxvf js-1.7.0.tar.gz&lt;br /&gt;    cd js/src&lt;br /&gt;    export CFLAGS="-DJS_C_STRINGS_ARE_UTF8"&lt;br /&gt;    make -f Makefile.ref&lt;br /&gt;    sudo JS_DIST=/usr make -f Makefile.ref export&lt;br /&gt;&lt;br /&gt;MongoDB installation:&lt;br /&gt;    git clone git://github.com/mongodb/mongo.git&lt;br /&gt;    scons all&lt;br /&gt;    sudo scons --prefix=/opt/mongo install&lt;br /&gt;&lt;br /&gt;Finishing up:&lt;br /&gt;    add /opt/mongo/bin to your path&lt;br /&gt;    create a /data/db directory structure and chown it to your user or add read-write permission.&lt;br /&gt;    http://www.howtogeek.com/howto/ubuntu/how-to-add-a-program-to-the-ubuntu-startup-list-after-login/&lt;br /&gt;        System -&gt; Preferences -&gt; Startup Applications -&gt; Startup Programs&lt;br /&gt;        click add, click browse and select /opt/mongo/bin/mongod&lt;br /&gt;        add run to the end of the line so that it reads '/opt/mongo/bin/mongod run'&lt;br /&gt;        enter name and comment then save&lt;br /&gt;&lt;br /&gt;And you're done. mongodb will start up with no authentication as default at localhost:27017, the web information interface is at localhost:28017. You can use mongo to enter the interactive shell, similar to mysql's shell client.&lt;br /&gt;&lt;br /&gt;Some links to get you started:&lt;br /&gt;http://www.mongodb.org/display/DOCS/Overview+-+The+MongoDB+Interactive+Shell&lt;br /&gt;http://www.mongodb.org/display/DOCS/File+Based+Configuration&lt;br /&gt;http://www.mongodb.org/display/DOCS/Command+Line+Parameters&lt;br /&gt;http://www.mongodb.org/display/DOCS/Security+and+Authentication&lt;br /&gt;http://www.mongodb.org/display/DOCS/Manual&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7903063970537375052?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7903063970537375052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7903063970537375052' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7903063970537375052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7903063970537375052'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2009/08/installing-mongodb-on-ubuntu-904-jaunty.html' title='Installing MongoDB on Ubuntu 9.04 Jaunty Jackalope'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-3570596928756338361</id><published>2009-03-17T17:56:00.003+08:00</published><updated>2010-03-30T10:33:36.678+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>Delegation for iphone-google-maps-component</title><content type='html'>The &lt;a href="http://code.google.com/p/iphone-google-maps-component/"&gt;iphone-google-maps-component&lt;/a&gt; is a way for you to use Google Maps on the iPhone through the use of an extended &lt;span style="font-style: italic;"&gt;UIWebView&lt;/span&gt; and an html file on a server somewhere that does the map loading.&lt;br /&gt;&lt;br /&gt;The present code overrides the default delegate &lt;span style="font-style: italic;"&gt;UIWebViewDelegate&lt;/span&gt; with its own, &lt;span style="font-style: italic;"&gt;MapWebViewDelegate&lt;/span&gt;. You cannot use the &lt;span style="font-style: italic;"&gt;setCenterWithLatLng&lt;/span&gt; to establish the starting location until the view has finished loading. With the override, the &lt;span style="font-style: italic;"&gt;webViewDidFinishLoad&lt;/span&gt; delegate method is unavailable.&lt;br /&gt;&lt;br /&gt;Going by this &lt;a href="http://groups.google.com/group/iphone-map-view/browse_thread/thread/1b5758eb15ae73fe/74a2c30e06d3dcea?lnk=gst&amp;amp;q=uiwebviewdelegate#74a2c30e06d3dcea"&gt;post&lt;/a&gt;, the following code changes will allow the use of both delegates.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;MapWebView.h&lt;/span&gt;&lt;br /&gt;1) Change protocol definition.&lt;br /&gt;&lt;code&gt;@protocol MapWebViewDelegate &amp;lt UIWebViewDelegate &amp;gt &lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;MapWebView.m&lt;/span&gt;&lt;br /&gt;2) Remove the synthesize line.&lt;br /&gt;&lt;code&gt;//@synthesize delegate;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;3) Replace with own methods, to hook into super.delegate.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;- (id &lt;mapwebviewdelegate&gt;) delegate {&lt;br /&gt;       return (id &lt;mapwebviewdelegate&gt;)super.delegate;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (void) setDelegate :(id &lt;mapwebviewdelegate&gt;) delegate {&lt;br /&gt;       super.delegate = delegate;&lt;br /&gt;}&lt;/mapwebviewdelegate&gt;&lt;/mapwebviewdelegate&gt;&lt;/mapwebviewdelegate&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;webViewDidFinishLoad&lt;/span&gt; should be accessible, as well as the other methods in the &lt;span style="font-style: italic;"&gt;UIWebViewDelegate&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Another way of setting the starting location is through the &lt;span style="font-style: italic;"&gt;loadMap&lt;/span&gt; method in &lt;span style="font-weight: bold;"&gt;MapWebView.h&lt;/span&gt;. The URL string can accept two more variables, latitude and longitude.&lt;br /&gt;&lt;br /&gt;Change this:&lt;br /&gt;&lt;code&gt;NSString *urlStr = [NSString stringWithFormat:&lt;br /&gt;        @"http://www.wenear.com/iphone-test?width=%d&amp;amp;height=%d&amp;amp;zoom=%d",&lt;br /&gt;        width, height, DEFAULT_ZOOM_LEVEL];&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;To this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;NSString *urlStr = [NSString stringWithFormat:&lt;br /&gt;   @"http://www.wenear.com/iphone-test?width=%d&amp;amp;height=%d&amp;amp;latitude=%f&amp;amp;longitude=%f&amp;amp;zoom=%d",&lt;br /&gt;   width, height, location.coordinate.latitude, location.coordinate.longitude, DEFAULT_ZOOM_LEVEL];&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Here, location is a &lt;span style="font-style: italic;"&gt;CLLocation&lt;/span&gt;, part of the &lt;span style="font-style: italic;"&gt;CoreLocation&lt;/span&gt; framework. The &lt;span style="font-style: italic;"&gt;loadMap&lt;/span&gt; method is publicly defined in the interface and it accepts location as its variable. The call in &lt;span style="font-style:italic;"&gt;didMoveToSuperview&lt;/span&gt; should be properly handled.&lt;br /&gt;&lt;br /&gt;The latitude and longitude are doubles and can be hardcoded instead.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-3570596928756338361?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/3570596928756338361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=3570596928756338361' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3570596928756338361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3570596928756338361'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2009/03/delegation-for-iphone-google-maps.html' title='Delegation for iphone-google-maps-component'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-9140926046411620177</id><published>2009-02-09T17:16:00.002+08:00</published><updated>2009-02-09T18:04:57.162+08:00</updated><title type='text'>XML and the Copyright symbol, ©</title><content type='html'>For anyone parsing an XMl file and wondering what in the world is an &lt;span style="font-weight: bold; font-style: italic;"&gt;org.xml.sax.SAXParseException: Invalid byte 1 of 1-byte UTF-8 sequence&lt;/span&gt; error message, check to see whether the XML file has any special characters like the copyright symbol, ©. The default encoding of UTF-8 will choke on these.&lt;br /&gt;&lt;br /&gt;Solved my woes by changing the encoding to &lt;code&gt;&lt;span style="font-weight:bold;"&gt;&amp;lt;?xml version="1.0" encoding="iso-8859-1"?&amp;gt;&lt;/span&gt;&lt;/code&gt; to get the character to display correctly. You can also filter it out or replace the symbol with its character reference.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-9140926046411620177?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/9140926046411620177/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=9140926046411620177' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/9140926046411620177'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/9140926046411620177'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2009/02/xml-and-copyright-symbol.html' title='XML and the Copyright symbol, ©'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8043662046474877510</id><published>2009-01-05T15:06:00.003+08:00</published><updated>2009-01-05T17:53:55.898+08:00</updated><title type='text'>Google Friend Connect &amp; Facebook Connect</title><content type='html'>&lt;h4&gt;Google Friend Connect&lt;/h4&gt;A Google, Yahoo, AIM or OpenID account can be used for authentication. &lt;br /&gt;&lt;br /&gt;You start it off with logging into your Google account and going to &lt;a href="http://www.google.com/friendconnect/"&gt;http://www.google.com/friendconnect/&lt;/a&gt;.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;From there, click on 'Set up a new site' and enter your site name and url.&lt;/li&gt;&lt;li&gt;You'll be given two files, &lt;i&gt;canvas.html&lt;/i&gt; and &lt;i&gt;rpc_relay.html&lt;/i&gt;, to copy onto your web site.&lt;/li&gt;&lt;li&gt;The last step is testing for those two files.&lt;/li&gt;&lt;/ul&gt;After that, it's a matter of choosing the gadgets you wish to add, customizing it and then copying the code generated into one of your site pages. The code is normal html and javascript.&lt;br /&gt;&lt;br /&gt;From the current gadgets available, you can add on to your site to make it more 'sociable', like knowing the site members, adding in a chat box and reviewing/rating stuff.&lt;br /&gt;&lt;br /&gt;You can create your own custom gadgets from these sites:&lt;br /&gt;&lt;a href="http://code.google.com/apis/gadgets/"&gt;http://code.google.com/apis/gadgets/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.google.com/apis/opensocial/"&gt;http://code.google.com/apis/opensocial/&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Facebook Connect&lt;/h4&gt;Only a Facebook account can be used for authentication.&lt;br /&gt;&lt;br /&gt;Login into your Facebook account and follow the instructions located here:&lt;br /&gt;&lt;a href="http://wiki.developers.facebook.com/index.php/Trying_Out_Facebook_Connect"&gt;http://wiki.developers.facebook.com/index.php/Trying_Out_Facebook_Connect&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The main page for developers for Facebook Connect is &lt;a href="http://developers.facebook.com/connect.php"&gt;http://developers.facebook.com/connect.php&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Facebook uses it's own &lt;a href="http://wiki.developers.facebook.com/index.php/FBML"&gt;Facebook Markup Language (FBML)&lt;/a&gt;, in contrast to normal HTML, to facilitate creation of all Facebook applications. Facebook Connect is therefore embedded into user pages using FBML.&lt;br /&gt;&lt;br /&gt;Facebook Connect is more of an expansion of Facebook onto other sites, depending on the application, it allows for data on a user site to be displayed back in Facebook.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://mashable.com/2008/12/11/facebook-connect-blog/?cp=2"&gt;HOW TO: Add Facebook Connect to Your Blog in 8 Minutes&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8043662046474877510?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8043662046474877510/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8043662046474877510' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8043662046474877510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8043662046474877510'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2009/01/google-friend-connect-facebook-connect.html' title='Google Friend Connect &amp; Facebook Connect'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8654222474523611320</id><published>2008-12-02T13:21:00.000+08:00</published><updated>2008-12-02T13:22:07.500+08:00</updated><title type='text'>Clickpass plugin for Grails, Part 2</title><content type='html'>Go to &lt;a href="http://clickpass.com/"&gt;Clickpass&lt;/a&gt; and create an account. Once in the account, go to the "My Details" tab and check the "Show software developer tools" under "&lt;span style="font-style:italic;"&gt;Additional Preferences&lt;/span&gt;". There should now be a "developer" tab present, select it and push the "Create new site" button.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1. Register site&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Type in the &lt;span style="font-style:italic;"&gt;site name&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style="font-weight:bold;"&gt;URL&lt;/span&gt;: http://localhost:8080/makedo&lt;/code&gt;. This is for running a grails app on your own machine named &lt;span style="font-style:italic;"&gt;makedo&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;span style="font-style:italic;"&gt;Description&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;logo&lt;/span&gt; are optional.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2. Log users in&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;span style="font-weight:bold;"&gt;OpenID trust root&lt;/span&gt;: http://localhost:8080&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style="font-weight:bold;"&gt;begin_openid_login&lt;/span&gt;: http://localhost:8080/makedo/openid/login?success_controller=&lt;br /&gt;clickpass&amp;success_action=welcome&amp;error_controller=&amp;error_action=&lt;/code&gt;. This link is where Clickpass will access, providing the OpenID details, after one has passed the bar that should be in the app.&lt;/li&gt;&lt;li&gt;Leave the &lt;span style="font-style:italic;"&gt;OpenID parameter label&lt;/span&gt; alone.&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style="font-weight:bold;"&gt;Submission method&lt;/span&gt;: POST&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;span style="font-style:italic;"&gt;SSL&lt;/span&gt; is optional.&lt;/li&gt;&lt;li&gt;Once you have saved the changes, the page will change and display a choice of clickpass bars and the html code for it down below. Copy the html code into &lt;code&gt;_clickpass.gsp&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3. Merge accounts&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;span style="font-weight:bold;"&gt;begin_add_openid_to_user URL&lt;/span&gt;: http://localhost:8080/makedo/clickpass/merge&lt;/code&gt;. This is after the authentication and the check whether the OpenID belongs to any user on the database, bringing him to the registration form. If the user selects to login a pre-existing account, the username and password he provides will be sent to this link. If successful the OpenID will be associated with that account.&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style="font-weight:bold;"&gt;user_id label&lt;/span&gt;: Username&lt;/code&gt;. This is for the login page Clickpass will provide before accessing the URL above. Merely cosmetic.&lt;/li&gt;&lt;li&gt;Adding the connect bar is optional.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;4. Register new signups&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;span style="font-weight:bold;"&gt;process_openid_registration_url&lt;/span&gt;: http://localhost:8080/makedo/clickpass/register&lt;/code&gt;. This is after the authentication and the check whether the OpenID belongs to any user on the database, bringing him to the registration form. The user provides information to Clickpass which will be passed along to the link. If successful a new user account with the associated OpenID will be created and saved in your app.&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style="font-weight:bold;"&gt;new_openid_completion_url&lt;/span&gt;: http://localhost:8080/makedo/clickpass/welcome&lt;/code&gt;. This is for when authentication is successful and all other things have been taken cared of, e.g. registration or merging.&lt;/li&gt;&lt;li&gt;The others are optional except for the fields. Changes in the fields may require changes in the register method of the Clickpass controller.&lt;/li&gt;&lt;li&gt;The URL for the registration form should be left for last as it changes due to the fields. Once you're satified and have saved the changes, you can copy and paste the string into &lt;code&gt;urlString&lt;/code&gt; in the welcome method of the Clickpass controller.&lt;/ul&gt;&lt;span style="font-weight:bold;"&gt;Aftermath&lt;/span&gt;&lt;br /&gt;Once the settings are done, you can use Clickpass.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8654222474523611320?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8654222474523611320/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8654222474523611320' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8654222474523611320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8654222474523611320'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/12/clickpass-plugin-for-grails-part-2.html' title='Clickpass plugin for Grails, Part 2'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7236973534317619400</id><published>2008-12-02T09:15:00.003+08:00</published><updated>2008-12-02T11:06:12.484+08:00</updated><title type='text'>Clickpass plugin for Grails, Part 1</title><content type='html'>Clickpass works by handling the OpenID authentication and sending it back to the site. This means that any Grails app using this plugin must also install the OpenID plugin. Also the site will need to be registered with Clickpass and some settings need to be set online. When the authenticated details are sent back, the user is logged in and sent to the welcome page, sent to a form for details to complete registration or asked to login to attach the OpenID to an existing user account.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;grails create-plugin &lt;span style="font-style: italic;"&gt;clickpass&lt;/span&gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Add &lt;code&gt;ClickpassController.groovy&lt;/code&gt; to &lt;code&gt;grails-app/controller&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Add &lt;code&gt;User.groovy&lt;/code&gt; to &lt;code&gt;grails-app/domain&lt;/code&gt;. This is a dummy file required for the plugin to be packaged.&lt;/li&gt;&lt;li&gt;Add &lt;code&gt;ClickpassTagLib.groovy&lt;/code&gt; to &lt;code&gt;grails-app/taglib&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Add &lt;code&gt;_clickpass.gsp&lt;/code&gt; to &lt;code&gt;grails-app/views&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Add &lt;code&gt;welcome.gsp&lt;/code&gt; to &lt;code&gt;grails-app/views/clickpass&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;ClickpassController.groovy&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;class ClickpassController {&lt;br /&gt;    def openidService&lt;br /&gt;&lt;br /&gt;    def index = { response.sendError(404) }&lt;br /&gt;&lt;br /&gt;    def welcome = {&lt;br /&gt;        def user = null&lt;br /&gt;  &lt;br /&gt; if (openidService.isLoggedIn(session)) {&lt;br /&gt;            user = User.findByOpenid(openidService.getIdentifier(session))&lt;br /&gt;            if (user == null) {&lt;br /&gt;                def urlString = "http://www.clickpass.com/process_new_openid?&lt;br /&gt;                    site_key=Xr2zelexGn&amp;amp;process_openid_registration_url=&lt;br /&gt;                    http%3A%2F%2Flocalhost%3A8080%2Fsocialr%2Fclickpass%2F&lt;br /&gt;                    register&amp;amp;new_openid_completion_url=http%3A%2F%2F&lt;br /&gt;                    localhost%3A8080%2Fsocialr%2Fclickpass%2Fwelcome&amp;amp;&lt;br /&gt;                    requested_fields=nickname%2Cemail&amp;amp;required_fields=&amp;amp;&lt;br /&gt;                    nickname_label=Nickname&amp;amp;email_label=Email"&lt;br /&gt;                redirect(url:urlString)&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    def merge = {&lt;br /&gt;        def user = User.findByUsernameAndPassword(params.user_id, params.password)&lt;br /&gt;        def urlredirect = &lt;br /&gt;            java.net.URLDecoder.decode(params.clickpass_merge_callback_url) + &lt;br /&gt;            "&amp;amp;userid_authenticated=false"   &lt;br /&gt;      &lt;br /&gt;        if (user == null) {&lt;br /&gt;            redirect(url:urlredirect)&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        user.openid = openidService.getIdentifier(session)&lt;br /&gt;&lt;br /&gt;        if (user.save()) {           &lt;br /&gt;            redirect(controller:'clickpass',action:'welcome')&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;            redirect(url:urlredirect)&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;  &lt;br /&gt;    def register = {&lt;br /&gt;        def user = new User()&lt;br /&gt;        user.username = params.nickname&lt;br /&gt;        user.email = params.email&lt;br /&gt;        user.openid = openidService.getIdentifier(session)&lt;br /&gt;        user.password = ''&lt;br /&gt;      &lt;br /&gt;        if (user.save()) {&lt;br /&gt;            flash.message = "Thank you for signing up."&lt;br /&gt;            redirect(controller:'clickpass', action:'welcome')&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;            flash.message = "There is a problem signing up."&lt;br /&gt;            redirect(controller:'clickpass', action:'index')&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;index:&lt;/code&gt; Nothing for the index to do so set up a 404.&lt;/li&gt;&lt;li&gt;&lt;code&gt;welcome:&lt;/code&gt; When a user is authenticated by OpenID, a search is made to see whether that OpenID is in the database, if not then redirect to the registration page. The &lt;code&gt;urlString&lt;/code&gt; is obtained from Clickpass so this needs to be changed for each site&lt;/li&gt;&lt;li&gt;&lt;code&gt;merge:&lt;/code&gt; A user, authenticated by OpenID, who wants to attach the ID to his account.&lt;/li&gt;&lt;li&gt;&lt;code&gt;register:&lt;/code&gt; Create a new user account with the OpenID and save it.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;User.groovy&lt;/span&gt;&lt;br /&gt;Nothing in it except for the class declaration.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;ClickpassTagLib.groovy&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;class ClickpassTagLib {&lt;br /&gt;    static namespace = "clickpass"&lt;br /&gt; &lt;br /&gt;    def bar = { attrs, body -&gt; &lt;br /&gt;        try {&lt;br /&gt;            out &lt;&lt; render(template:"/clickpass", contextPath:"${pluginContextPath}")&lt;br /&gt;        }&lt;br /&gt;        catch(Exception e) {&lt;br /&gt;            log.error(e)&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The namespace allows one to use it, i.e &lt;code&gt;&amp;lt;clickpass:&lt;span style="font-style: italic;"&gt;foobar&lt;/span&gt;/&amp;gt;&lt;/code&gt;, in the code instead of the generic &lt;code&gt;&amp;lt;g:&lt;span style="font-style: italic;"&gt;foobar&lt;/span&gt;/&amp;gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;For usage in an app, all that is required is &lt;code&gt;&amp;lt;clickpass:bar/&amp;gt;&lt;/code&gt; to be inserted into the html.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;/&lt;/code&gt; in the template name is necessary to revert the path to the project base, otherwise it would go looking in the main app &lt;code&gt;views&lt;/code&gt; folder.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;contextPath:"${pluginContextPath}"&lt;/code&gt; is not mentioned in the documention but after setting the path to the base, this sets it to the correct plugin &lt;code&gt;views&lt;/code&gt; folder.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;_clickpass.gsp&lt;/span&gt;&lt;br /&gt;The html for this is generated by Clickpass, after registering your site, you can just copy and paste. This creates the Clickpass login bar.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;welcome.gsp&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;html&amp;gt;&lt;br /&gt;    &amp;lt;head&amp;gt;&lt;br /&gt;        &amp;lt;link rel="openid.server" href="http://www.clickpass.com/openid_server" /&amp;gt;&lt;br /&gt;        &amp;lt;link rel="openid.delegate" href="http://clickpass.com/public/iseec" /&amp;gt; &lt;br /&gt;        &amp;lt;title&amp;gt;Welcome&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;/head&amp;gt;&lt;br /&gt;    &amp;lt;body&amp;gt;&lt;br /&gt;        &amp;lt;h1&gt;Welcome&amp;lt;/h1&amp;gt;&lt;br /&gt;        &amp;lt;openid:identifier /&amp;gt; &lt;br /&gt;        &amp;lt;openid:ifLoggedIn&amp;gt;&lt;br /&gt;            &amp;lt;openid:logoutLink&amp;gt;Logout&amp;lt;/openid:logoutLink&amp;gt;&lt;br /&gt;        &amp;lt;/openid:ifLoggedIn&amp;gt;&lt;br /&gt;    &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;/code&gt;&lt;ul&gt;&lt;li&gt;This is a simple welcome page after the user successfully logs in and his account is verified.&lt;/li&gt;&lt;li&gt;One can replace it with their own or redirect from this page.&lt;/li&gt;&lt;li&gt;The OpenID is displayed as well as a logout link.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Aftermath&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;grails package-plugin&lt;/code&gt; to get it all into a zip file.&lt;/li&gt;&lt;li&gt;&lt;code&gt;grails install-plugin /path/to/plugin/grails-example-0.1.zip&lt;/code&gt; to install it into an app.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7236973534317619400?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7236973534317619400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7236973534317619400' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7236973534317619400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7236973534317619400'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/12/clickpass-plugin-for-grails-part-1.html' title='Clickpass plugin for Grails, Part 1'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-9085663789246342588</id><published>2008-10-24T10:50:00.003+08:00</published><updated>2008-10-24T16:17:18.324+08:00</updated><title type='text'>IPhone MoviePlayer Sample Code 4</title><content type='html'>&lt;h3&gt;MyOverlayView&lt;/h3&gt;&lt;h3&gt;Interface&lt;/h3&gt;Instance methods:&lt;ul&gt;&lt;li&gt;-(void)awakeFromNib;&lt;/li&gt;&lt;li&gt;-(void)dealloc;&lt;/li&gt;&lt;li&gt;-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Implementation&lt;/h3&gt;Imports:&lt;ul&gt;&lt;li&gt;&lt;code&gt;#import "MyViewController.h"&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;i&gt;-(void)awakeFromNib&lt;/i&gt;&lt;br /&gt;Rotate the overlay 90 degrees clockwise then translate it to the centre of the screen. This will match the orientation the movie player uses, full-screen landscape mode.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;-(void)dealloc&lt;/i&gt;&lt;br /&gt;Call super &lt;code&gt;dealloc&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event&lt;/i&gt;&lt;br /&gt;Similar to the &lt;code&gt;MyImageView&lt;/code&gt; implementation. This creates a &lt;code&gt;OverlayViewTouchNotification&lt;/code&gt; and fires it off.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-9085663789246342588?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/9085663789246342588/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=9085663789246342588' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/9085663789246342588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/9085663789246342588'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/10/iphone-movieplayer-sample-code-4.html' title='IPhone MoviePlayer Sample Code 4'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-2492098171545144980</id><published>2008-10-24T10:11:00.002+08:00</published><updated>2008-10-24T10:50:52.228+08:00</updated><title type='text'>IPhone MoviePlayer Sample Code 3</title><content type='html'>&lt;h3&gt;MyImageView&lt;/h3&gt;&lt;h3&gt;Interface&lt;/h3&gt;Imports:&lt;ul&gt;&lt;li&gt;&lt;code&gt;#import "MyViewController.h"&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;Instance variables:&lt;ul&gt;&lt;li&gt;&lt;code&gt;mViewController&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;Instance methods:&lt;ul&gt;&lt;li&gt;&lt;code&gt;-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Implementation&lt;/h3&gt;&lt;i&gt;-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event&lt;/i&gt;&lt;br /&gt;Receives a set with the touches and the event. Gets a &lt;code&gt;UITouch&lt;/code&gt; from the set and check it's &lt;code&gt;phase&lt;/code&gt;. If it's &lt;code&gt;UITouchPhaseBegan&lt;/code&gt;, play the movie.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-2492098171545144980?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/2492098171545144980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=2492098171545144980' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2492098171545144980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2492098171545144980'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/10/iphone-movieplayer-sample-code-3.html' title='IPhone MoviePlayer Sample Code 3'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-1958729594129306994</id><published>2008-10-23T14:11:00.004+08:00</published><updated>2008-10-24T16:18:41.710+08:00</updated><title type='text'>IPhone MoviePlayer Sample Code 2</title><content type='html'>&lt;h3&gt;MyViewController&lt;/h3&gt;&lt;h3&gt;Interface&lt;/h3&gt;Imports:&lt;ul&gt;&lt;li&gt;&lt;code&gt;#import &amp;lt MediaPlayer/MediaPlayer.h &amp;gt&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;#import "MyOverlayView.h"&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;The line '&lt;code&gt;extern NSString * const OverlayViewTouchNotification&lt;/code&gt;' creates a global constant that will be used for touches to the overlay view. Any class importing &lt;code&gt;MyViewController&lt;/code&gt; can access this variable.&lt;br /&gt;&lt;br /&gt;Instance variables:&lt;ul&gt;&lt;li&gt;&lt;code&gt;mMoviePlayer (MPMoviePlayerController)&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;mMovieURL (NSURL)&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;mOverlayView (MyOverlayView)&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;Instance methods:&lt;ul&gt;&lt;li&gt;&lt;code&gt;-(NSURL *)movieURL;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;-(void)initMoviePlayer;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;-(IBAction)playMovie:(id)sender;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;-(void)overlayViewTouches:(NSNotification *)notification;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;-(IBAction)overlayViewButtonPress:(id)sender;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Implementation&lt;/h3&gt;Imports:&lt;ul&gt;&lt;li&gt;#import "MoviePlayerAppDelegate.h"&lt;/li&gt;&lt;/ul&gt;Initialise constant &lt;code&gt;OverlayViewTouchNotification&lt;/code&gt; with the string '&lt;code&gt;overlayViewTouch&lt;/code&gt;'.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;#pragma&lt;/code&gt; is a compiler directive. However the compiler ignores it if &lt;a href="http://macdevelopertips.com/xcode/xcode-and-pragma-mark.html"&gt;&lt;code&gt;#pragma mark&lt;/code&gt;&lt;/a&gt; is used. &lt;a href="http://cocoasamurai.blogspot.com/2006/09/tip-pragma-mark-organizing-your-source.html"&gt;&lt;code&gt;#pragma mark&lt;/code&gt;&lt;/a&gt; helps with the organisation of your methods in the Xcode dropdown list.&lt;br /&gt;&lt;br /&gt;'&lt;code&gt;#pragma mark -&lt;/code&gt;' divvies up the methods by creating a spacer line while '&lt;code&gt;#pragma mark Movie Player Routines&lt;/code&gt;' creates a bold label with the text 'Movie Player Routines'.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Movie Player Routines&lt;/b&gt;&lt;br /&gt;&lt;i&gt;- (void) moviePreloadDidFinish:(NSNotification*)notification&lt;br /&gt;- (void) moviePlayBackDidFinish:(NSNotification*)notification&lt;br /&gt;- (void) movieScalingModeDidChange:(NSNotification*)notification&lt;/i&gt;&lt;br /&gt;These are events. When they are triggered is evident from the names. There is no code inside them.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;-(void)initMoviePlayer&lt;/i&gt;&lt;ul&gt;&lt;li&gt;Register &lt;code&gt;MPMoviePlayerContentPreloadDidFinishNotification&lt;/code&gt; (named after the definition in MPMoviePlayerController.h) with &lt;code&gt;NSNotificationCenter&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The movie player object, &lt;code&gt;mMoviePlayer&lt;/code&gt;, is created by allocating &lt;code&gt;MPMoviePlayerController&lt;/code&gt; and initialising it with &lt;code&gt;movieURL&lt;/code&gt;.&lt;/li&gt;&lt;li&gt; Register &lt;code&gt;MPMoviePlayerPlaybackDidFinishNotification&lt;/code&gt; and &lt;Code&gt;MPMoviePlayerScalingModeDidChangeNotification&lt;/code&gt;, giving &lt;code&gt;mMoviePlayer&lt;/code&gt; as the notification sender.&lt;/li&gt;&lt;li&gt;Obtain the &lt;code&gt;MoviePlayerAppDelegate&lt;/code&gt; object and use its instance variables to set &lt;code&gt;mMoviePlayer&lt;/code&gt;.&lt;/li&gt;&lt;li&gt; Register &lt;code&gt;OverlayViewTouchNotification&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;i&gt;-(IBAction)playMovie:(id)sender&lt;/i&gt;&lt;ul&gt;&lt;li&gt;Play &lt;code&gt;mMoviePlayer&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Get the application windows in an array.&lt;/li&gt;&lt;li&gt;Get the movie player window.&lt;/li&gt;&lt;li&gt;Add &lt;code&gt;mOverlayView&lt;/code&gt; as the subview of the movie player window.&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;View Controller Routines&lt;/b&gt;&lt;br /&gt;&lt;i&gt;-(NSURL *)movieURL&lt;/i&gt;&lt;ul&gt;&lt;li&gt;Check &lt;code&gt;mMovieURL&lt;/code&gt; whether it's null or not.&lt;/li&gt;&lt;li&gt;Passing will return &lt;code&gt;mMovieURL&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Failing will get the main bundle, look for 'Movie.m4v', check it and convert the path to &lt;code&gt;NSURL&lt;/code&gt; before assigning it to &lt;code&gt;movieURL&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;i&gt;-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation &lt;br /&gt;-(void)didReceiveMemoryWarning&lt;br /&gt;-(void)overlayViewTouches:(NSNotification *)notification&lt;br /&gt;-(IBAction)overlayViewButtonPress:(id)sender&lt;/i&gt;&lt;br /&gt;Trivial or empty methods.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;-(void)dealloc&lt;/i&gt;&lt;br /&gt;Remove all registered notifications and release the movie player.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-1958729594129306994?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/1958729594129306994/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=1958729594129306994' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1958729594129306994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1958729594129306994'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/10/iphone-movieplayer-sample-code-2.html' title='IPhone MoviePlayer Sample Code 2'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4943188712054624155</id><published>2008-10-23T10:15:00.007+08:00</published><updated>2008-10-23T14:08:40.616+08:00</updated><title type='text'>IPhone MoviePlayer Sample Code</title><content type='html'>Deconstructing the &lt;a href="http://developer.apple.com/iphone/library/samplecode/MoviePlayer_iPhone/index.html"&gt;MoviePlayer app&lt;/a&gt; to see how the Media Player Framework ticks.&lt;br /&gt;&lt;br /&gt;MoviePlayer has 4 classes: &lt;ul&gt;&lt;li&gt;&lt;code&gt;MoviePlayerAppDelegate&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;MyImageView&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;MyOverlayView&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;MyViewController&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;A new IPhone application automatically creates 2 classes, with project name &lt;code&gt;MPC&lt;/code&gt;, &lt;code&gt;MPCAppDelegate&lt;/code&gt; and &lt;code&gt;MPCViewController&lt;/code&gt;. Therefore, &lt;code&gt;MyImageView&lt;/code&gt; and &lt;code&gt;MyOverlayView&lt;/code&gt; are additions while &lt;code&gt;MyViewController&lt;/code&gt; has been renamed.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;MoviePlayerAppDelegate&lt;/h3&gt;&lt;h3&gt;Interface&lt;/h3&gt;There are 2 different ways of including a file/class:&lt;ul&gt;&lt;li&gt;&lt;code&gt;#import "MyViewController.h"&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;@class MyViewController;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;The interface lists 3 instance variables of type &lt;code&gt;NSInteger&lt;/code&gt; aside from the default &lt;code&gt;UIWindow&lt;/code&gt; and &lt;code&gt;ViewController&lt;/code&gt;:&lt;ul&gt;&lt;li&gt;&lt;code&gt;backgroundColor&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;controlMode&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;scalingMode&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;The &lt;code&gt;@property&lt;/code&gt; declares the accessor methods for the 5 variables. It has attributes which modify the accessors.&lt;br /&gt;&lt;br /&gt;Example: &lt;code&gt;@property (nonatomic, retain) UIWindow *window;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;nonatomic&lt;/code&gt; means the accessor returns the value directly, the default is to lock, get value, unlock which is meant for multithreaded environments.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;assign&lt;/code&gt;, &lt;code&gt;retain&lt;/code&gt; or &lt;code&gt;copy&lt;/code&gt; must be explicitly set if garbage collection is not used. &lt;code&gt;assign&lt;/code&gt; is the default and means the setter uses a simple assignment. &lt;code&gt;retain&lt;/code&gt; keeps the object variable in-memory and cannot be deallocated without your permission. &lt;code&gt;copy&lt;/code&gt; means that a copy of the object should be used for assignment and the previous one is sent a release message.&lt;br /&gt;&lt;br /&gt;3 instance methods:&lt;ul&gt;&lt;li&gt;&lt;code&gt;-(void)setUserSettingsDefaults;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;-(void)applicationDidFinishLaunching:(UIApplication *)application;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;-(void)dealloc;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Implementation&lt;/h3&gt;3 NSString keys:&lt;ul&gt;&lt;li&gt;&lt;code&gt;kScalingModeKey = @"scalingMode"&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;kControlModeKey = @"controlMode"&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;kBackgroundColorKey = @"backgroundColor"&lt;/li&gt;&lt;/code&gt;&lt;/ul&gt;&lt;code&gt;@synthesize&lt;/code&gt; generates the accessors according to the attributes listed. If implemented manually, the code must follow what has been specified in the &lt;code&gt;@property&lt;/code&gt;. &lt;code&gt;@synthesize&lt;/code&gt; will only generate accessors that don't exist so if a variable has a setter already, then only a getter will be generated.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;code&gt;-(void)setUserSettingsDefaults&lt;/code&gt;&lt;/i&gt;&lt;br /&gt;Sets up a test calling &lt;code&gt;NSUserDefaults&lt;/code&gt; to see if there's a match. Passing will set the &lt;code&gt;scalingMode&lt;/code&gt;, &lt;code&gt;controlMode&lt;/code&gt; and &lt;code&gt;backgroundColor&lt;/code&gt; variables. Failing will create the values based on the settings bundle info and then set the variables:&lt;ul&gt;&lt;li&gt;Get the path to the main bundle of the project.&lt;/li&gt;&lt;li&gt;Append &lt;code&gt;Settings.bundle&lt;/code&gt; to the path using &lt;code&gt;stringByAppendingPathComponent&lt;/code&gt;, which takes care of adding separators.&lt;/li&gt;&lt;li&gt;Append &lt;code&gt;Root.plist&lt;/code&gt; to the path, same as before.&lt;/li&gt;&lt;li&gt;Create a dictionary using &lt;code&gt;dictionaryWithContentsOfFile&lt;/code&gt;, giving the path to &lt;code&gt;Root.plist&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Create the &lt;code&gt;prefSpecifierArray&lt;/code&gt; array from the dictionary using the key, &lt;code&gt;PreferenceSpecifiers&lt;/code&gt;, which is a tag in &lt;code&gt;Root.plist&lt;/code&gt;.&lt;ul&gt;&lt;li&gt;&lt;code&gt;Root.plist&lt;/code&gt; is an XML file with dict, array and key tags. May be an easy way to &lt;a href="http://cocoadevcentral.com/articles/000059.php"&gt;read XML&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Declare 3 &lt;code&gt;NSNumber&lt;/code&gt; variables and a dictionary, &lt;code&gt;prefItem&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Loop &lt;code&gt;prefSpecifierArray&lt;/code&gt; with the current value going into &lt;code&gt;prefItem&lt;/code&gt;.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Set &lt;code&gt;keyValueStr&lt;/code&gt; with the dictionary using the key, &lt;code&gt;'Key'&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Set &lt;code&gt;defaultValue&lt;/code&gt; with the dictionary using the key, &lt;code&gt;'DefaultValue'&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Check if &lt;code&gt;keyValueStr&lt;/code&gt; is equal to any &lt;code&gt;NSStrings&lt;/code&gt; specified above.&lt;/li&gt;&lt;li&gt;Set the numbers with &lt;code&gt;defaultValue&lt;/code&gt; if any is correct.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Create a dictionary containing the default values and their keys.&lt;/li&gt;&lt;li&gt;Register the dictionary with &lt;code&gt;NSUserDefaults&lt;/code&gt; using &lt;code&gt;registerDefaults&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Updates and writes to the persistent domains using &lt;code&gt;synchronize&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;i&gt;&lt;code&gt;-(void)applicationDidFinishLaunching:(UIApplication *)application&lt;/code&gt;&lt;/i&gt;&lt;br /&gt;Add the &lt;code&gt;ViewController&lt;/code&gt;'s view as a subview of the &lt;code&gt;UIWindow&lt;/code&gt;. Call self with &lt;code&gt;setUserSettingsDefaults&lt;/code&gt; to get the default movie player settings. Lastly, call the &lt;code&gt;ViewController&lt;/code&gt; with &lt;code&gt;initMoviePlayer&lt;/code&gt; to create a movie player object.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;code&gt;-(void)dealloc&lt;/code&gt;&lt;/i&gt;&lt;br /&gt;Release the &lt;code&gt;UIWindow&lt;/code&gt; and the &lt;code&gt;ViewController&lt;/code&gt;. Call the super's &lt;code&gt;dealloc&lt;/code&gt; method.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4943188712054624155?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4943188712054624155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4943188712054624155' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4943188712054624155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4943188712054624155'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/10/iphone-movieplayer-sample-code.html' title='IPhone MoviePlayer Sample Code'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-3215223351398053932</id><published>2008-10-21T16:16:00.005+08:00</published><updated>2008-10-22T11:32:32.694+08:00</updated><title type='text'>Objective-C Classes</title><content type='html'>Objective-C (Obj-C) is C with Object Oriented Programming tacked on. The object syntax takes some time to get used to, as it is decidedly different from the normal C++/Java syntax.&lt;br /&gt;&lt;br /&gt;There are two parts for an object in Obj-C, which are the interface and the implementation. The parts should be stored separately, the interface in a header file (*.h) and the implementation is a *.m file.&lt;br /&gt;&lt;br /&gt;The interface stores the instance variables and the prototypes for the class and instance methods. The implementation defines those methods.&lt;br /&gt;&lt;br /&gt;Sample code:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;*** CounterController.h ***&lt;br /&gt;#import &amp;lt Cocoa/Cocoa.h &amp;gt&lt;br /&gt;@interface CounterController : NSObject {&lt;br /&gt;IBOutlet id display_update;&lt;br /&gt;int count;&lt;br /&gt;}&lt;br /&gt;- (IBAction)minus_button_pushed:(id)sender;&lt;br /&gt;- (IBAction)p10_button_pushed:(id)sender;&lt;br /&gt;- (IBAction)plus_button_pushed:(id)sender;&lt;br /&gt;@end&lt;br /&gt;&lt;br /&gt;*** CounterController.m ***&lt;br /&gt;#import "CounterController.h"&lt;br /&gt;@implementation CounterController&lt;br /&gt;- (IBAction)minus_button_pushed:(id)sender {&lt;br /&gt;count--;&lt;br /&gt;[display_update setIntValue:count];&lt;br /&gt;}&lt;br /&gt;- (IBAction)p10_button_pushed:(id)sender {&lt;br /&gt;count+=10;&lt;br /&gt;[display_update setIntValue:count];&lt;br /&gt;}&lt;br /&gt;- (IBAction)plus_button_pushed:(id)sender {&lt;br /&gt;count++;&lt;br /&gt;[display_update setIntValue:count];&lt;br /&gt;}&lt;br /&gt;@end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Things of note:&lt;ul&gt;&lt;li&gt;Obj-C uses &lt;code&gt;import&lt;/code&gt; instead of &lt;code&gt;include&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The class &lt;code&gt;CounterController&lt;/code&gt; is a subclass of &lt;code&gt;NSObject&lt;/code&gt;.&lt;/li&gt;&lt;li&gt; Inside the brackets are the instance variables &lt;code&gt;display_update&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;IBOutlet&lt;/code&gt; before &lt;code&gt;display_update&lt;/code&gt; means the &lt;code&gt;display_update&lt;/code&gt; is an output on the GUI display in the &lt;b&gt;Interface Builder&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;id&lt;/code&gt; is a general type, meaning any object.&lt;/li&gt;&lt;li&gt; &lt;code&gt;(IBAction)minus_button_pushed:(id)sender&lt;/code&gt; translates to &lt;code&gt;IBAction minus_button_pushed(id sender)&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;-&lt;/code&gt; before the methods classify them as instance methods, &lt;code&gt;+&lt;/code&gt; for class methods.&lt;/li&gt;&lt;li&gt;The brackets &lt;code&gt;[]&lt;/code&gt; indicate messaging, &lt;code&gt;[display_update setIntValue:count]&lt;/code&gt; translates to &lt;code&gt;display_update.setIntValue(count).&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.gmonline.demon.co.uk/cscene/CS7/CS7-05.html"&gt;http://www.gmonline.demon.co.uk/cscene/CS7/CS7-05.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Objective-C"&gt;http://en.wikipedia.org/wiki/Objective-C&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.otierney.net/objective-c.html"&gt;http://www.otierney.net/objective-c.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-3215223351398053932?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/3215223351398053932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=3215223351398053932' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3215223351398053932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3215223351398053932'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/10/objective-c-classes.html' title='Objective-C Classes'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4676130919395609148</id><published>2008-08-22T09:40:00.002+08:00</published><updated>2008-08-22T12:13:58.148+08:00</updated><title type='text'>Grails - JSecurity plugin</title><content type='html'>JSecurity is a Grails plugin that adds authentication and authorization to a web application. First we go about creating a project and installing the plugin:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;grails create-app &lt;span style="font-style: italic;"&gt;project_name&lt;/span&gt;&lt;br /&gt;grails install-plugin jsecurity&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Then we use the &lt;code&gt;quick-start&lt;/code&gt; option, available once the plugin is installed, to generate JSecurity domain classes, controller and realm.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;grails quick-start&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;We can follow the &lt;a href="http://grails.org/JSecurity+Plugin+-+Quick+Start"&gt;JSecurity Quick Start&lt;/a&gt; guide to create a functional security application or use the files present to customize and only take what is required.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;span style="font-weight: bold;"&gt;Authentication&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;For the login authentication, we'll need the &lt;code&gt;User&lt;/code&gt; class, the &lt;code&gt;Auth&lt;/code&gt; controller and the &lt;code&gt;DbRealm&lt;/code&gt;.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The &lt;code&gt;User&lt;/code&gt; class will need a username and password field. The password field must be hashed, SHA1 is the default.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;For the &lt;code&gt;Auth&lt;/code&gt; controller, the important methods are &lt;code&gt;signIn&lt;/code&gt; and &lt;code&gt;signOut&lt;/code&gt;. For &lt;code&gt;signIn&lt;/code&gt;, the important lines are the &lt;code&gt;authToken&lt;/code&gt; definition, the &lt;code&gt;jsecSecurityManager&lt;/code&gt; login and the &lt;code&gt;try-catch&lt;/code&gt; block.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Authentication occurs in the &lt;code&gt;DbRealm&lt;/code&gt;. The important lines in the &lt;code&gt;authenticate&lt;/code&gt; method are the &lt;code&gt;account&lt;/code&gt; definition and the &lt;code&gt;credentialMatch&lt;/code&gt;. You may customize the &lt;code&gt;authToken&lt;/code&gt; class by changing the &lt;code&gt;static&lt;/code&gt; line, replacing the default with your own class. &lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;credentialMatch&lt;/code&gt; defaults to SHA1 hashing, to change it, modify &lt;code&gt;grails-app/conf/spring/resources.groovy&lt;/code&gt; and add the line &lt;code&gt;credentialMatcher(org.jsecurity.authc.credential.&lt;span style="font-style: italic;"&gt;hashMatcher&lt;/span&gt;)&lt;/code&gt;. Replace &lt;code&gt;&lt;span style="font-style: italic;"&gt;hashMatcher&lt;/span&gt;&lt;/code&gt; with the hash class of your choice.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;&lt;span style="font-weight: bold;"&gt;Roles&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;Roles depend on the hasRole method of the realm. This method accepts a principal, usually a username, and a rolename. The output is a simple true or false boolean, making the logic inside the method completely up to the programmer. The classes generated by the quick-start are not all necessary. We can easily use a variable in the user class to determine the role, modifying the hasRole method as required, thus no additional classes are needed.&lt;br /&gt;&lt;br /&gt;For this project, we are using the default &lt;code&gt;hasRole&lt;/code&gt; method and keeping the &lt;code&gt;Role&lt;/code&gt; as well as the &lt;code&gt;UserRoleRel&lt;/code&gt; class. This, along with the &lt;code&gt;User&lt;/code&gt; class, allows us to have users and roles, assigning the users to a role in a many-to-one relationship. Refer to the &lt;a href="http://grails.org/JSecurity+Plugin+-+Quick+Start"&gt;JSecurity Quick Start&lt;/a&gt; guide for the way to bootstrap it.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;span style="font-weight: bold;"&gt;Authorization&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;Having users and roles, we can now set up proper access control by creating a security filter file, &lt;code&gt;grails-app/conf/SecurityFilters.groovy&lt;/code&gt;. Filter rules cannot overlap in actions, just modify the &lt;code&gt;accessControl&lt;/code&gt; to include the desired roles. The rules return true or false, allowing or denying access.&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;&lt;span style="font-weight: bold;"&gt;Security Filter Example&lt;/span&gt;&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;import org.jsecurity.SecurityUtils&lt;br /&gt;// Customise the interceptor behaviour by implementing onNotAuthenticated() and onUnauthorized() methods in your filters class.&lt;br /&gt;// Default behaviour remains as before (redirect to login page for an unauthenticated user, redirect to unauthorized page for unauthorized access).&lt;br /&gt;class SecurityFilters {&lt;br /&gt; def filters = {&lt;br /&gt;//   Ensure that all controllers and actions require an authenticated user,&lt;br /&gt;//   except for a few controllers&lt;br /&gt;    auth(controller: "*", action: "*") {&lt;br /&gt;       before = {&lt;br /&gt;//            Exclude these controllers.&lt;br /&gt;          if ((controllerName == "search" &amp;amp;&amp;amp; actionName == "unboundSearch") || (controllerName == "business" &amp;amp;&amp;amp; actionName == "show") ||&lt;br /&gt;          (controllerName == "user" &amp;amp;&amp;amp; actionName == "signup")) return true&lt;br /&gt;            &lt;br /&gt;//            This just means that the user must be authenticated. He does&lt;br /&gt;//            not need any particular role or permission.&lt;br /&gt;          accessControl { true }&lt;br /&gt;       }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;//      Roles return true or false&lt;br /&gt;//      Add reviews to businesses. Only Administrators or Users can do this&lt;br /&gt;    addReview(controller: "review", action: "create") {&lt;br /&gt;       before = {&lt;br /&gt;          accessControl {&lt;br /&gt;             role("Administrator") || role("User")&lt;br /&gt;          }&lt;br /&gt;       }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;//      Add pets to users&lt;br /&gt;    addPets(controller: "pet", action: "(create|save)") {&lt;br /&gt;       before = {&lt;br /&gt;          accessControl {&lt;br /&gt;             def user = User.findByUserName(SecurityUtils.subject.principal)&lt;br /&gt;             def allowAccess = false&lt;br /&gt;&lt;br /&gt;             if (role("Administrator")) {&lt;br /&gt;                allowAccess = true&lt;br /&gt;             }&lt;br /&gt;             else if (params.id.toLong() == user.id) {&lt;br /&gt;                allowAccess = role("Business User") || role("User")&lt;br /&gt;             }&lt;br /&gt;             return allowAccess&lt;br /&gt;          }&lt;br /&gt;       }&lt;br /&gt;    }&lt;br /&gt; }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;&lt;span style="font-weight: bold;"&gt;Permissions&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;Permissions offer finer access control, like read, update, delete. Roles can be considered as named collections of permissions, like administrator, user, superuser. Nothing was done with permissions, it was entirely a role-based affair. Refer to the documentation for usage.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;span style="font-weight: bold;"&gt;Links&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.grails.org/JSecurity+Plugin"&gt;JSecurity Plugin&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.grails.org/JSecurity+Plugin+-+Quick+Start"&gt;JSecurity Plugin - Quick Start Guide&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.grails.org/JSecurity+Release+Notes"&gt;JSecurity Release Notes&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://josh-in-antarctica.blogspot.com/2008/05/writing-simple-issue-tracker-in-grails.html"&gt;Writing a Simple Issue Tracker in Grails, Part 2&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4676130919395609148?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4676130919395609148/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4676130919395609148' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4676130919395609148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4676130919395609148'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/08/grails-jsecurity-plugin.html' title='Grails - JSecurity plugin'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6100250582309023470</id><published>2008-07-16T08:38:00.002+08:00</published><updated>2008-07-16T09:51:26.412+08:00</updated><title type='text'>GSP training</title><content type='html'>Brought Fauzan up to speed on the project work that's been done, explaining the search controller and the gsp code.&lt;br /&gt;&lt;br /&gt;He made a simplified version of the search page, recreating the basic functionality.&lt;br /&gt;&lt;br /&gt;The CSS was not touched on. I figure one can just strip it from the page and into a file then figure out where to put and call the file.&lt;br /&gt;&lt;br /&gt;Similarly the javascript, dealing with the Google map functionality, may be moved to a file and referred to. It may not work due to the gsp tags inside the code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6100250582309023470?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6100250582309023470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6100250582309023470' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6100250582309023470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6100250582309023470'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/07/gsp-training.html' title='GSP training'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6333275905149289479</id><published>2008-06-26T17:24:00.002+08:00</published><updated>2008-06-26T17:55:16.820+08:00</updated><title type='text'>TWiki Replication</title><content type='html'>Setup a backup TWiki by using rsync, cron and public key authentication. Had problems getting cron to run on root since a normal user does not have the permissions necessary. Solved them when I realized I do need the account active (as I had ignored the expired warning when logging in as root).&lt;br /&gt;&lt;br /&gt;Made little headway with regards to the MixTape build on hudson (reminder: change the SVN location once migration is finished). Installed the Flex 3 SDK and used it to compile the mxml files. However the swf files do not seem to work.&lt;br /&gt;&lt;br /&gt;The grails search plugin sets up easily. Run 'grails install-plugin searchable', add 'static searchable = true' to any domain class, add data and run the app. The default allows you to search the fields of the domain class, objects may need a specific mapping though.&lt;br /&gt;&lt;br /&gt;In the process of migrating SVN projects from one repository to another.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6333275905149289479?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6333275905149289479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6333275905149289479' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6333275905149289479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6333275905149289479'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/06/twiki-replication.html' title='TWiki Replication'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-2246053734427783289</id><published>2008-05-28T12:41:00.005+08:00</published><updated>2008-06-20T11:04:33.415+08:00</updated><title type='text'>Flex File Upload using Grails Backend</title><content type='html'>This file upload application is based off the one by Nocturnal at &lt;a href="http://weblog.cahlan.com/2006/12/flex-upload-component.html"&gt;Coding Cowboys&lt;/a&gt;, a Flex client with a PHP backend. The client has been stripped down to it's core functions and PHP replaced with a Grails backend.&lt;br /&gt;&lt;br /&gt;The Grails backend is a file controller with an action defined:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;def upload = {&lt;br /&gt;  if(request.method == 'POST') {&lt;br /&gt;    Iterator itr = request.getFileNames();&lt;br /&gt;     &lt;br /&gt;    while(itr.hasNext()) {&lt;br /&gt;      MultipartFile file = request.getFile(itr.next());&lt;br /&gt;      File destination = new File(file.getOriginalFilename())&lt;br /&gt;      &lt;br /&gt;      if (!file.isEmpty()) {&lt;br /&gt;      file.transferTo(destination)&lt;br /&gt;//       success&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;//    failure&lt;br /&gt;      }&lt;br /&gt;     }&lt;br /&gt;     &lt;br /&gt;//     Trigger an Event.COMPLETE event, notifying the Flex client&lt;br /&gt;     response.sendError(200,'Done');&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is capable of uploading multiple files at once and can be tested using a view gsp:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;    &amp;lt;head&amp;gt;&lt;br /&gt;        &amp;lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&amp;gt;&lt;br /&gt;        &amp;lt;meta name="layout" content="main" /&amp;gt;&lt;br /&gt;        &amp;lt;title&amp;gt;Test Upload&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;/head&amp;gt;&lt;br /&gt;    &amp;lt;body&amp;gt;&lt;br /&gt;        &amp;lt;div class="body"&amp;gt;&lt;br /&gt;            &amp;lt;h1&amp;gt;Upload File&amp;lt;/h1&amp;gt;&lt;br /&gt;            &amp;lt;g:form method="post" action="upload" enctype="multipart/form-data"&amp;gt;&lt;br /&gt;             &amp;lt;input type="file" name="file_1"/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;             &amp;lt;input type="file" name="file_2"/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;             &amp;lt;input type="file" name="file_3"/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;             &amp;lt;input type="file" name="file_4"/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;             &amp;lt;input type="file" name="file_5"/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;             &amp;lt;input type="submit"/&amp;gt;&lt;br /&gt;            &amp;lt;/g:form&amp;gt;&lt;br /&gt;        &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The Flex client has been pared down to 3 main functions, adding files to the upload list, removing them from the list and finally uploading the files to the server.&lt;br /&gt;&lt;br /&gt;First the imports, global variables and initializer:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;import mx.controls.*;&lt;br /&gt;import mx.managers.*;&lt;br /&gt;import mx.events.*;&lt;br /&gt;import flash.events.*;&lt;br /&gt;import flash.net.*;&lt;br /&gt;   &lt;br /&gt;// Convention: Underscore to differentiate global and local variables&lt;br /&gt;private var _refAddFiles:FileReferenceList;&lt;br /&gt;private var _refUploadFile:FileReference;&lt;br /&gt;private var _arrUploadFiles:Array;&lt;br /&gt;private var _numCurrentUpload:Number;&lt;br /&gt;&lt;br /&gt;private function initApp():void {&lt;br /&gt; _refAddFiles = new FileReferenceList();&lt;br /&gt; _refAddFiles.addEventListener(Event.SELECT, onSelectFile);&lt;br /&gt; _arrUploadFiles = new Array();&lt;br /&gt; _numCurrentUpload = 0;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The add-files function opens the browse window and enable the selection of one or more files to add to the upload list:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;// Called to add file(s) for upload&lt;br /&gt;// The fileList property is populated anew each time browse() is called on that FileReferenceList object.&lt;br /&gt;private function addFiles():void {&lt;br /&gt; _refAddFiles.browse();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Called when file(s) are selected&lt;br /&gt;private function onSelectFile(event:Event):void {&lt;br /&gt; // Add files to _arrUploadFiles&lt;br /&gt; if (_refAddFiles.fileList.length &gt;= 1) {    &lt;br /&gt;  for (var k:Number = 0; k &lt; _refAddFiles.fileList.length; k++) {&lt;br /&gt;   _arrUploadFiles.push({&lt;br /&gt;    name:_refAddFiles.fileList[k].name,&lt;br /&gt;    size:formatFileSize(_refAddFiles.fileList[k].size),&lt;br /&gt;    file:_refAddFiles.fileList[k]});&lt;br /&gt;  }&lt;br /&gt;  listFiles.dataProvider = _arrUploadFiles;&lt;br /&gt;  listFiles.selectedIndex = _arrUploadFiles.length - 1;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The remove-files function:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private function removeFiles():void {&lt;br /&gt; var arrSelected:Array = listFiles.selectedIndices;&lt;br /&gt; if (arrSelected.length &gt;= 1) {&lt;br /&gt;  // Null selected files&lt;br /&gt;  for (var i:Number = 0; i &lt; arrSelected.length; i++) {&lt;br /&gt;   _arrUploadFiles[Number(arrSelected[i])] = null;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  // Remove the null entries&lt;br /&gt;  for (var j:Number = 0; j &lt; _arrUploadFiles.length; j++) {&lt;br /&gt;   if (_arrUploadFiles[j] == null) {&lt;br /&gt;    _arrUploadFiles.splice(j, 1);&lt;br /&gt;    j--;&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  listFiles.dataProvider = _arrUploadFiles;&lt;br /&gt;  listFiles.selectedIndex = 0;     &lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The upload function is where the point of integration with Grails is, in the request calling up the controller. Although the Grails backend can handle multiple files, Flex can only initiate the upload one file at a time. The event listener and the return response in the Grails controller allow the upload function to loop:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private function uploadFiles():void {&lt;br /&gt; if (_arrUploadFiles.length &gt; 0) {&lt;br /&gt;  listFiles.selectedIndex = _numCurrentUpload;&lt;br /&gt;  &lt;br /&gt;  var request:URLRequest = new URLRequest();&lt;br /&gt;  request.data = sendVars;&lt;br /&gt;     request.url = "http://localhost:8080/App/file/upload";&lt;br /&gt;     request.method = URLRequestMethod.POST;&lt;br /&gt;     _refUploadFile = new FileReference();&lt;br /&gt;     _refUploadFile = listFiles.selectedItem.file;&lt;br /&gt;     _refUploadFile.addEventListener(Event.COMPLETE, onUploadComplete);&lt;br /&gt;     _refUploadFile.upload(request, "file", false);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private function onUploadComplete(event:Event):void {&lt;br /&gt; _numCurrentUpload++;&lt;br /&gt; if (_numCurrentUpload &lt; _arrUploadFiles.length) {&lt;br /&gt;  uploadFiles();&lt;br /&gt; } else {&lt;br /&gt;  _numCurrentUpload = 0;&lt;br /&gt;  _arrUploadFiles = new Array();&lt;br /&gt;  listFiles.dataProvider = _arrUploadFiles;&lt;br /&gt;  listFiles.selectedIndex = 0;&lt;br /&gt;  Alert.show("Files have been uploaded", "Upload Complete");&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And lastly the UI:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;mx:Panel title="Files Upload" width="100%" height="100%"&amp;gt;&lt;br /&gt; &amp;lt;mx:DataGrid id="listFiles" allowMultipleSelection="true" verticalScrollPolicy="on"&lt;br /&gt;  draggableColumns="false" resizableColumns="false" sortableColumns="false" width="100%" height="100%"&amp;gt;&lt;br /&gt;  &amp;lt;mx:columns&amp;gt;&lt;br /&gt;   &amp;lt;mx:DataGridColumn headerText="File" dataField="name" wordWrap="true"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:columns&amp;gt;&lt;br /&gt; &amp;lt;/mx:DataGrid&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;mx:ControlBar&amp;gt;&lt;br /&gt;  &amp;lt;mx:Button label="Add" click="addFiles()"/&amp;gt;&lt;br /&gt;  &amp;lt;mx:Button label="Remove" click="removeFiles()"/&amp;gt;&lt;br /&gt;  &amp;lt;mx:Button label="Upload" click="uploadFiles()"/&amp;gt;&lt;br /&gt; &amp;lt;/mx:ControlBar&amp;gt;&lt;br /&gt;&amp;lt;/mx:Panel&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The Flex mxml/swf files must be moved to the web-app folder of the Grails project and the embedded Jetty activated by 'grails run-app' in order to run this application.&lt;br /&gt;&lt;br /&gt;The files will be uploaded to the project directory and thus are not accessible by the webapp. The line to amend is in the Grails controller:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;File destination = new File("web-app/" + file.getOriginalFilename())&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Note this only works while the project is in development mode. For war files, the base directory would depend on where the server is started, usually in the server home directory. So for a standalone Jetty server, the path to add would be "&lt;code&gt;webapps/App/&lt;/code&gt;".&lt;br /&gt;&lt;br /&gt;Using the war file in a Tomcat server has been problematic. Only one file can be successfully uploaded to the server, there is no looping. &lt;br /&gt;&lt;br /&gt;Links:&lt;br /&gt;&lt;a href="http://weblog.cahlan.com/2006/12/flex-upload-component.html"&gt;Coding Cowboys: Flex upload component&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Flex Client:&lt;br /&gt;http://livedocs.adobe.com/flex/3/langref/flash/net/URLRequest.html&lt;br /&gt;http://livedocs.adobe.com/flex/3/langref/flash/net/FileReference.html&lt;br /&gt;http://livedocs.adobe.com/flex/3/langref/flash/net/FileReferenceList.html&lt;br /&gt;http://livedocs.adobe.com/flex/3/html/help.html?content=17_Networking_and_communications_7.html&lt;br /&gt;&lt;br /&gt;Grails Backend:&lt;br /&gt;http://www.grails.org/Controllers+-+File+Uploads&lt;br /&gt;http://docs.codehaus.org/display/GRAILS/File+Upload&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-2246053734427783289?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/2246053734427783289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=2246053734427783289' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2246053734427783289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2246053734427783289'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/flex-file-upload-using-grails-backend.html' title='Flex File Upload using Grails Backend'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4778875064653009588</id><published>2008-05-23T16:36:00.002+08:00</published><updated>2008-05-23T17:11:59.260+08:00</updated><title type='text'>Flex Training - Last bit</title><content type='html'>Used list-based controls that accept a data array and display out depending on design.  Then dealt with data forms, accepting user input, validating it and supposedly entering it into the database.&lt;br /&gt;&lt;br /&gt;The last bit was how to create a release version of the Flex application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4778875064653009588?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4778875064653009588/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4778875064653009588' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4778875064653009588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4778875064653009588'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/flex-training-last-bit.html' title='Flex Training - Last bit'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4382428224170685037</id><published>2008-05-22T17:16:00.002+08:00</published><updated>2008-05-22T17:45:09.341+08:00</updated><title type='text'>Flex Training - Dynamic Data</title><content type='html'>Read an XML file using a HTTPService and displayed it. Autogenerated a PHP XML service based on database contents previously inserted. The Flex application was supposed to use the service to access the data in the database and display it on the page. However seems there's a problem with the service.&lt;br /&gt;&lt;br /&gt;The videos make use of &lt;a href="http://www.mamp.info/en/index.php"&gt;MAMP&lt;/a&gt;, a Mac-Apache-MySQL-PHP all-in-one webserver. There may be conflicts with the MySQL that was previously installed and the MAMP's version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4382428224170685037?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4382428224170685037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4382428224170685037' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4382428224170685037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4382428224170685037'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/flex-training-dynamic-data.html' title='Flex Training - Dynamic Data'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8265442309540042102</id><published>2008-05-21T18:19:00.002+08:00</published><updated>2008-05-21T18:49:09.239+08:00</updated><title type='text'>Flex Training - Debugging and Event Handling</title><content type='html'>Debugging - How to set breakpoints and traces (logging to console). The breakpoints suspend the application, allowing one to see the variables and objects present at that particular time.&lt;br /&gt;&lt;br /&gt;Event Handling - Dealing with events and how to listen for them. One can also create custom events. With a breakpoint, the anatomy of an event can be explored, showing the specific variables and the inherited ones that make up the event.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8265442309540042102?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8265442309540042102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8265442309540042102' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8265442309540042102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8265442309540042102'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/flex-training-debugging-and-event.html' title='Flex Training - Debugging and Event Handling'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-5352797298178125993</id><published>2008-05-20T18:12:00.002+08:00</published><updated>2008-05-20T18:41:47.702+08:00</updated><title type='text'>Flex Training - 3 chapters down</title><content type='html'>Learned layouts, CSS and layered views.&lt;br /&gt;&lt;br /&gt;VBox, HBox, Canvas and Panel layouts place their content vertically, horizontally or using absolute positioning.&lt;br /&gt;&lt;br /&gt;A feature of the Flex CSS is embedding font(s) into the application so that the look remains the same for all. The drawback to that is the increased size of the application.&lt;br /&gt;&lt;br /&gt;There are three layered view components, the ViewStack, TabNavigator (which extends ViewStack) and Accordian. The latter two contain their own switching mechanism, the first has to include in custom code utilizing the selectedIndex or selectedChild properties or one of these four bars: TabBar, LinkBar, ButtonBar and ToggleButtonBar.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-5352797298178125993?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/5352797298178125993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=5352797298178125993' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5352797298178125993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5352797298178125993'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/flex-training-3-chapters-down.html' title='Flex Training - 3 chapters down'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4292393735275832907</id><published>2008-05-16T16:51:00.003+08:00</published><updated>2008-05-16T17:23:36.283+08:00</updated><title type='text'>Flex Training - Of custom components and state changes</title><content type='html'>Went through the creation of a basic custom component and how to use it in a application project.&lt;br /&gt;&lt;br /&gt;More information on the Design perspective, explaining the different areas such as the properties and controls. Designed view states that allow a login form to become a register form by a push of a button and vice versa.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4292393735275832907?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4292393735275832907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4292393735275832907' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4292393735275832907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4292393735275832907'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/flex-training-of-custom-components-and.html' title='Flex Training - Of custom components and state changes'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-3406370946686513576</id><published>2008-05-14T16:39:00.002+08:00</published><updated>2008-05-14T17:15:56.512+08:00</updated><title type='text'>Flex Training - Day 2</title><content type='html'>Going into interesting territory. An explanation of the current programming language used, ActionScript 3, is given along with how MXML translates to it and vice versa. It then shows the visual design and their controls, correlating it with the mxml source that shows up as you drag and drop controls on the design.&lt;br /&gt;&lt;br /&gt;Found out what was up with the bindable tags that are appended to ActionScript variables. Bindable enables a variable to broadcast its content when updated, alerting the elements that listen for and display or use such content. By default ActionScript variables are not bindable and each and every one must be appended for all to be bindable. MXML variables (eg. mx:Number) are automatically bindable however.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-3406370946686513576?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/3406370946686513576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=3406370946686513576' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3406370946686513576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3406370946686513576'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/flex-training-day-2.html' title='Flex Training - Day 2'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-5938987042069297003</id><published>2008-05-13T17:08:00.002+08:00</published><updated>2008-05-13T17:36:47.425+08:00</updated><title type='text'>Flex Training</title><content type='html'>Assisting in VMWare Server, Ubuntu 8.04 Server edition and Drupal installation took up the better part of the day. The Server edition was not necessary, however the Desktop edition downloaded cannot be used due to corruption/incomplete transfer. The advantage of the Server edition is that it allows the setup of the mail, LAMP and OpenSSH servers automatically, thus mail works and ssh to the installed OS is possible. The downside is that the user interface is the command-line. This is rectified by following &lt;a href="http://ubuntuforums.org/showthread.php?t=186298&amp;page=2"&gt;How to install GNOME on Ubuntu Server&lt;br /&gt;&lt;/a&gt; specifically these lines:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;sudo apt-get update&lt;br /&gt;&lt;br /&gt;sudo apt-get install ubuntu-desktop&lt;br /&gt;sudo apt-get install gdm&lt;br /&gt;sudo /etc/init.d/gdm start&lt;br /&gt;sudo dpkg-reconfigure xserver-xorg&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The resulting download is over 300MB, so it will take some time to finish with the process. In the meanwhile, one will have to suffer with the command-line ;).&lt;br /&gt;&lt;br /&gt;After that, &lt;a href="http://movielibrary.lynda.com/html/modPage.asp?ID=438"&gt;Flex training&lt;/a&gt; took up the rest of the day. Started out on the easy side, going over the 'Introduction' and 'Getting Started' videos. Mostly reinforcing what was already known, though there were a few interesting bits, like making full use of a two-monitor setup by detaching some of the Flex windows from the main application and putting it in the spare screen area. Then one can save that perspective and reuse it. It is applicable to Eclipse as well, seeing that the Flex Builder is built on it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-5938987042069297003?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/5938987042069297003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=5938987042069297003' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5938987042069297003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5938987042069297003'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/flex-training.html' title='Flex Training'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6235517575798740325</id><published>2008-05-07T17:36:00.002+08:00</published><updated>2008-05-07T17:49:02.041+08:00</updated><title type='text'>Fisheye</title><content type='html'>Found the effect we're looking demoing &lt;a href="http://demo.quietlyscheming.com/fisheye/index.html"&gt;here&lt;/a&gt;. The actual component is found &lt;a href="http://flexbox.mrinalwadhwa.com/"&gt;here&lt;/a&gt;. Now to discover how to include it in the project.&lt;br /&gt;&lt;br /&gt;Links of Interest:&lt;br /&gt;&lt;a href="http://drupal.org/node/118136"&gt;Example: Flex Recipe App MXML for Drupal&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6235517575798740325?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6235517575798740325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6235517575798740325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6235517575798740325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6235517575798740325'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/fisheye.html' title='Fisheye'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-1705418324274699870</id><published>2008-05-06T16:45:00.003+08:00</published><updated>2008-05-07T13:27:38.690+08:00</updated><title type='text'>Flex and Drupal</title><content type='html'>The services module is responsible for exposing the Drupal data to any external app, with the amfphp module adding that particular functionality. The image, img_assist, pathauto and token modules are used to add images and text descriptions to Drupal. The views module has methods available in the services module, making it convinient to call.&lt;br /&gt;&lt;br /&gt;Pulling the data from drupal yields a filepath for the image, the actual file is displayed by adding the IP address to the filepath, e.g. &lt;i&gt;http://10.10.3.131/drupal5/files/images/pic.jpg&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Links of interest:&lt;br /&gt;&lt;a href="http://devzone.zend.com/article/2660-Reading-And-Writing-Drupal-With-Flex"&gt;Reading And Writing Drupal With Flex&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.cyberciti.biz/tips/howto-ubuntu-linux-convert-dhcp-network-configuration-to-static-ip-configuration.html"&gt;Howto: Ubuntu Linux convert DHCP network configuration to static IP configuration&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-1705418324274699870?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/1705418324274699870/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=1705418324274699870' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1705418324274699870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1705418324274699870'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/flex-and-drupal.html' title='Flex and Drupal'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8480816038510992962</id><published>2008-05-05T16:51:00.002+08:00</published><updated>2008-05-05T17:39:22.185+08:00</updated><title type='text'>Setting up a test Drupal site</title><content type='html'>The old Gutsy Gibbon VM was totally screwed up so the Hardy Heron server edition was installed on a new one. It has Drupal 5.7 in the apt-get packages and so installation was a breeze. One thing it should have mentioned was the need to hit the install page, &lt;code&gt;http://&lt;i&gt;ip&lt;/i&gt;/drupal5/install.php&lt;/code&gt;, to initialize the db and everything else.&lt;br /&gt;&lt;br /&gt;Turning clean urls on was as simple as typing two lines of code:&lt;br /&gt;&lt;code&gt;sudo a2enmod rewrite&lt;br /&gt;sudo /etc/init.d/apache2 restart&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then testing the clean urls and turning it on. This may be Ubuntu-specific though.&lt;br /&gt;&lt;br /&gt;A bunch of modules were downloaded and installed:&lt;br /&gt;amfphp&lt;br /&gt;cck&lt;br /&gt;image&lt;br /&gt;img_assist&lt;br /&gt;pathauto&lt;br /&gt;services&lt;br /&gt;swfaddress&lt;br /&gt;token&lt;br /&gt;views&lt;br /&gt;&lt;br /&gt;The amfphp is a plugin that requires the implementation available &lt;a href="http://sourceforge.net/projects/amfphp/"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8480816038510992962?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8480816038510992962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8480816038510992962' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8480816038510992962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8480816038510992962'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/setting-up-test-drupal-site.html' title='Setting up a test Drupal site'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8444557024251772148</id><published>2008-05-02T16:18:00.002+08:00</published><updated>2008-05-02T17:24:45.463+08:00</updated><title type='text'>Dupal CMS with Flash/Flex Frontend</title><content type='html'>Found a site, &lt;a href="http://cascadingstyle.net/"&gt;cascadingStyle&lt;/a&gt;, that talks about Druplash and Druplex (Drupal-powered Flash and Flex) sites and has a &lt;a href="http://www.cascadingstyle.net/files/presentations/DrupalConPresentation.pdf"&gt;presentation pdf&lt;/a&gt; available on that subject. The pdf lists two sites, &lt;a href="http://www.stevenmerrilltenor.com/"&gt;Steven W. Merrill, Tenor&lt;/a&gt; and &lt;a href="http://www.martin-eng.com/"&gt;Martin Engineering&lt;/a&gt;, running on Drupal+Flash.&lt;br /&gt;&lt;br /&gt;Three Drupal modules, &lt;a href="http://drupal.org/project/swfaddress"&gt;SWFAddress&lt;/a&gt;, &lt;a href="http://drupal.org/project/services"&gt;Services&lt;/a&gt;, &lt;a href="http://drupal.org/project/amfphp"&gt;AMFPHP&lt;/a&gt; are required to go about 'flashing' the site.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://modern-carpentry.com/talk/?p=32"&gt;Here&lt;/a&gt; is another take on the subject, using the same modules.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8444557024251772148?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8444557024251772148/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8444557024251772148' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8444557024251772148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8444557024251772148'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/05/dupal-cms-with-flashflex-frontend.html' title='Dupal CMS with Flash/Flex Frontend'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4814097641608953995</id><published>2008-04-30T16:49:00.003+08:00</published><updated>2008-05-02T16:17:56.715+08:00</updated><title type='text'>TaskMaster - Day 10</title><content type='html'>The new user can be added to the project or task and data already entered is preserved. This is done by removing the form's default save action and implementing actions for each and every submit button. The submit button will dump the data into the params map and all that is required is to store/forward it along then retrieve it back afterwards.&lt;br /&gt;&lt;br /&gt;The new user is to be notified by an email containing a link back to the project/task. The messagingService is responsible for this but has not yet been created.&lt;br /&gt;&lt;br /&gt;More information &lt;a href="http://fauzan-azzam.blogspot.com/2008/04/almost-finished-woohoo.html"&gt;here&lt;/a&gt; :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4814097641608953995?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4814097641608953995/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4814097641608953995' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4814097641608953995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4814097641608953995'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/taskmaster-day-10.html' title='TaskMaster - Day 10'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-166994265125290741</id><published>2008-04-29T16:53:00.003+08:00</published><updated>2008-04-30T09:10:43.204+08:00</updated><title type='text'>TaskMaster - Day 9</title><content type='html'>When in the task or project creation page, a new user may be created given just an email address and name. Unfortunately, redirecting to the user creation page wipes out any data entered in the task/project pages. So far there has been no way of saving the data.&lt;br /&gt;&lt;br /&gt;More information &lt;a href="http://fauzan-azzam.blogspot.com/2008/04/sorry-fans-forgot-to-post-my-blog.html"&gt;here&lt;/a&gt; :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-166994265125290741?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/166994265125290741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=166994265125290741' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/166994265125290741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/166994265125290741'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/taskmaster-day-9.html' title='TaskMaster - Day 9'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-1040370052459096400</id><published>2008-04-28T16:24:00.003+08:00</published><updated>2008-04-29T08:13:21.247+08:00</updated><title type='text'>TaskMaster - Day 8</title><content type='html'>Finally added the user members to the project. Used a custom tag &lt;a href="http://grails.codehaus.org/Contribute+a+Tag#ContributeaTag-checkBoxList"&gt;here&lt;/a&gt; that displays a list of checkboxes.&lt;br /&gt;&lt;br /&gt;Also cleared the validation and a few other stuff.&lt;br /&gt;&lt;br /&gt;More information &lt;a href="http://fauzan-azzam.blogspot.com/2008/04/how-do-i-save-form-entries-when.html"&gt;here&lt;/a&gt; :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-1040370052459096400?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/1040370052459096400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=1040370052459096400' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1040370052459096400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1040370052459096400'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/taskmaster-day-8.html' title='TaskMaster - Day 8'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-3335946201113552704</id><published>2008-04-25T16:45:00.003+08:00</published><updated>2008-04-28T16:55:12.324+08:00</updated><title type='text'>TaskMaster - Day 7</title><content type='html'>Managed to clear a minor issue but hit a wall with the adding of members to a project, there does not seem to be any good examples covering the view interface for a 1:m relationship. Much frustration.&lt;br /&gt;&lt;br /&gt;So right now there are three major issues, the messaging service, instant creation of a user for task or project inclusion and addition of members to projects.&lt;br /&gt;&lt;br /&gt;More information &lt;a href="http://fauzan-azzam.blogspot.com/2008/04/one-more-bug.html"&gt;here&lt;/a&gt; :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-3335946201113552704?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/3335946201113552704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=3335946201113552704' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3335946201113552704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3335946201113552704'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/taskmaster-day-7.html' title='TaskMaster - Day 7'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6970665582951173298</id><published>2008-04-24T16:53:00.003+08:00</published><updated>2008-04-25T09:07:12.362+08:00</updated><title type='text'>TaskMaster - Day 6</title><content type='html'>Spruced up the views, changing or removing elements and code.&lt;br /&gt;&lt;br /&gt;Aside from the MessagingService, which can't take off without a mail server, there are a few story issues. One is the adding of members to a project, figuring out how to do it. Another is to auto-create a non-existing user so that he may be added to a project or assigned a task, later on the user needs to complete his registration.&lt;br /&gt;&lt;br /&gt;Still to tackle the validation problem.&lt;br /&gt;&lt;br /&gt;It &lt;a href="http://fauzan-azzam.blogspot.com/2008/04/blogs-alive-again-d.html"&gt;lives!&lt;/a&gt; :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6970665582951173298?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6970665582951173298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6970665582951173298' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6970665582951173298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6970665582951173298'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/taskmaster-day-6.html' title='TaskMaster - Day 6'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6867765552324007359</id><published>2008-04-23T16:10:00.003+08:00</published><updated>2008-04-23T16:52:59.786+08:00</updated><title type='text'>TaskMaster - Day 5</title><content type='html'>Added in some sample data. Made a few changes to the login and registration pages as well as creating a navigation bar. Validation of the registration data does not seem to follow the constraints listed in the domain model. The project creation page needs to be tweaked, to allow members to be added in.&lt;br /&gt;&lt;br /&gt;The views in Grails are where all the presentation elements are present, with the controllers chipping in the model and the business logic. Whereas in Wicket, the presentation elements are coded and inserted through the placeholder ids which had been seeded in the HTML. Grails entails more time in HTMLland than is the case with Wicket.&lt;br /&gt;&lt;br /&gt;Creating the war file for the project is a simple one-liner: &lt;code&gt;grails war&lt;/code&gt;. This beats having to fuss around your own ant script and making sure all dependencies are being added. Now to find out how to change the version number on the war file, being stuck at 0.1.&lt;br /&gt;&lt;br /&gt;Reading up on the messaging service, &lt;a href="http://grails.codehaus.org/A+simple+EmailerService"&gt;this&lt;/a&gt; seems a simple way of doing it.&lt;br /&gt;&lt;br /&gt;The other blog is dead :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6867765552324007359?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6867765552324007359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6867765552324007359' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6867765552324007359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6867765552324007359'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/taskmaster-day-5.html' title='TaskMaster - Day 5'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8501972349341375765</id><published>2008-04-22T08:54:00.003+08:00</published><updated>2008-04-22T16:49:11.019+08:00</updated><title type='text'>TaskMaster - Day 4</title><content type='html'>Two services were created, AuthenticationService and MessagingService. The former service is used for logging in users (especially later on when the authentication methods increase, e.g LDAP, OpenID) and the latter service is to email users for whatever purposes.&lt;br /&gt;&lt;br /&gt;A BaseController was created to add in an interceptor and the authorization to all controllers via inheritance:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def beforeInterceptor = [action:this.&amp;auth, except:['login', 'logout', 'register']]&lt;br /&gt;&lt;br /&gt;def auth() { &lt;br /&gt;    if(!session.user) {&lt;br /&gt;        redirect(controller:'user',action:'login') &lt;br /&gt;            return false &lt;br /&gt;    } &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Cobbled together a working rough login and registration page. The controllers and views will be the focus from now on.&lt;br /&gt;&lt;br /&gt;The other blog is on hiatus for the moment :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8501972349341375765?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8501972349341375765/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8501972349341375765' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8501972349341375765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8501972349341375765'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/taskmaster-day-4.html' title='TaskMaster - Day 4'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-5891668313605285983</id><published>2008-04-21T16:23:00.003+08:00</published><updated>2008-04-22T08:34:54.358+08:00</updated><title type='text'>TaskMaster - Day 3</title><content type='html'>Refined testing, splitting the various CRUD activities into different test methods. Said activity took up the whole day, squashing failures as they turn up.&lt;br /&gt;&lt;br /&gt;Regarding the dates previously, switched to using the dateCreated and lastUpdated variables as GORM handles the timestamping with those variables automatically. There is another date variable that now works fine, making the past problem a head-scratching puzzle.&lt;br /&gt;&lt;br /&gt;Next up is the service tier. On that note, found a nice Grails CRUD example at &lt;a href="http://infoq.com/minibooks/grails"&gt;http://infoq.com/minibooks/grails&lt;/a&gt;. The PDF at that site shows how to create a Racetrack CRUD.&lt;br /&gt;&lt;br /&gt;More information &lt;a href="http://fauzan-azzam.blogspot.com/2008/04/finished-testing.html"&gt;here&lt;/a&gt; :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-5891668313605285983?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/5891668313605285983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=5891668313605285983' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5891668313605285983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5891668313605285983'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/taskmaster-day-3.html' title='TaskMaster - Day 3'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-1544285177227085997</id><published>2008-04-18T08:51:00.002+08:00</published><updated>2008-04-21T08:13:42.902+08:00</updated><title type='text'>TaskMaster - Day 2</title><content type='html'>Today was testing day. Having previously done no testing on Grails, there was some reading involved. Much frustration was involved in trying to get the test to run. There was light at the end of the tunnel when &lt;a href="http://grails.org/doc/1.0.x/guide/9.%20Testing.html#9.3%20Functional%20Testing"&gt;this&lt;/a&gt;, under the section 'Testing Domain Classes' was found. Basically the need to flush while saving, to make sure it all flows to the database.&lt;br /&gt;&lt;br /&gt;The light that was the flush was quickly snuffed out by the bold, hated 'FAILURE' from the test run. Much despair ensued. After some gritting of teeth and grinding of stone, the reason for the failed test surfaced. Apparently dates are not welcomed and with their exclusion, 'SUCCESS' was assured.&lt;br /&gt;&lt;br /&gt;Now to properly build the test classes...&lt;br /&gt;&lt;br /&gt;More information (or not) &lt;a href="http://fauzan-azzam.blogspot.com/2008/04/testing-testing-testing.html"&gt;here&lt;/a&gt; :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-1544285177227085997?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/1544285177227085997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=1544285177227085997' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1544285177227085997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1544285177227085997'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/taskmaster-day-2.html' title='TaskMaster - Day 2'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7577181797229980576</id><published>2008-04-17T17:06:00.002+08:00</published><updated>2008-04-18T09:17:06.738+08:00</updated><title type='text'>TaskMaster - Day 1</title><content type='html'>TaskMaster is an issue-tracking system, in the image of Bugzilla, to be developed using Grails. This is mostly a development project for training.&lt;br /&gt;&lt;br /&gt;Eclipse is used as the development IDE. Integration with &lt;a href="http://groovy.codehaus.org/Eclipse+Plugin"&gt;Groovy&lt;/a&gt; and &lt;a href="http://grails.org/Eclipse+IDE+Integration"&gt;Grails&lt;/a&gt; needed to be set up.&lt;br /&gt;&lt;br /&gt;The first day was spent sketching out the domain model, with three primary classes; User, Task and Project. Users are assigned Tasks to do and Projects are user groups for a particular purpose.&lt;br /&gt;&lt;br /&gt;A few problems came up regarding testing and checking into SVN.&lt;br /&gt;&lt;br /&gt;More information &lt;a href="http://fauzan-azzam.blogspot.com/2008/04/first-day.html"&gt;here&lt;/a&gt; :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7577181797229980576?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7577181797229980576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7577181797229980576' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7577181797229980576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7577181797229980576'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/taskmaster-day-1.html' title='TaskMaster - Day 1'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-5535494445793089487</id><published>2008-04-15T11:36:00.005+08:00</published><updated>2008-04-15T15:34:19.750+08:00</updated><title type='text'>J2ME Development on OSX</title><content type='html'>This follows the &lt;a href="http://today.java.net/pub/a/today/2005/02/09/j2me1.html?page=2"&gt;tutorial on java.net&lt;/a&gt;, which shows how to compile and package J2ME apps manually via the command-line.&lt;br /&gt;&lt;br /&gt;First, a wireless toolkit (J2ME SDK) is needed. The &lt;a href="http://mpowerplayer.com/"&gt;mpowerplayer&lt;/a&gt; toolkit supports OSX and it comes with a preverifier. The &lt;a href="http://microemu.org/"&gt;MicroEmulator&lt;/a&gt; toolkit has a better emulator than mpowerplayer though.&lt;br /&gt;&lt;br /&gt;Once a source file is provided, it is compiled by:&lt;br /&gt;&lt;code&gt;javac -bootclasspath /&lt;i&gt;path&lt;/i&gt;/cldc-1.1.jar:/&lt;i&gt;path&lt;/i&gt;/midp-2.0.jar /&lt;i&gt;package&lt;/i&gt;/&lt;i&gt;path&lt;/i&gt;/Source.java&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;bootclasspath&lt;/code&gt; option uses the specified library files for the compilation, instead of the normal Java environment.&lt;br /&gt;&lt;br /&gt;The next step is to preverify the class:&lt;br /&gt;&lt;code&gt;&lt;i&gt;mpowerplayer-folder&lt;/i&gt;/osx/preverify/preverify -classpath /&lt;i&gt;path&lt;/i&gt;/cldc-1.1.jar:/&lt;i&gt;path&lt;/i&gt;/midp-2.0.jar &lt;i&gt;package&lt;/i&gt;.&lt;i&gt;name&lt;/i&gt;.Source&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The preverifier default is to create a folder called &lt;i&gt;output&lt;/i&gt; with the same package structure in the current directory. The preverified file is placed there.&lt;br /&gt;&lt;br /&gt;In the &lt;i&gt;output&lt;/i&gt; folder, create a &lt;i&gt;Manifest.mf&lt;/i&gt; with the following:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;MIDlet-Name: Source&lt;br /&gt;MIDlet-Version: 1.0.0&lt;br /&gt;MIDlet-Vendor: NameMe&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Also in the &lt;i&gt;output&lt;/i&gt; folder, create a jar file:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;jar cvfm Source.jar Manifest.mf ./com&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The penultimate step is to create a jad file descriptor, Source.jad, with the following:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;MIDlet-1: Source, , &lt;i&gt;package&lt;/i&gt;.&lt;i&gt;name&lt;/i&gt;.Source&lt;br /&gt;MIDlet-Name: Source&lt;br /&gt;MIDlet-Version: 1.0.0&lt;br /&gt;MIDlet-Vendor: NameMe&lt;br /&gt;MIDlet-Jar-URL: Source.jar&lt;br /&gt;MIDlet-Jar-Size:&lt;br /&gt;MicroEdition-Profile: MIDP-2.0&lt;br /&gt;MicroEdition-Configuration: CLDC-1.1&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The last step is to fill in &lt;code&gt;MIDlet-Jar-Size&lt;/code&gt; with the actual number of bytes the jar file takes up. This completes compiling and packaging.&lt;br /&gt;&lt;br /&gt;Testing the packaged app in an emulator:&lt;br /&gt;&lt;code&gt;java -jar &lt;i&gt;microemulator-folder&lt;/i&gt;/microemulator.jar Source.jad&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Allowing the default behaviour of downloading the jad file, which then installs the jar file, set the &lt;code&gt;MIDlet-Jar-URL&lt;/code&gt; to:&lt;br /&gt;&lt;code&gt;http://&lt;i&gt;domain&lt;/i&gt;/&lt;i&gt;url&lt;/i&gt;/Source.jar&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Sites of Interest:&lt;br /&gt;&lt;a href="http://javablog.co.uk/2007/08/29/j2me-development-on-os-x/"&gt;&lt;br /&gt;J2ME Development on OS X&lt;/a&gt;&lt;br /&gt;&lt;a href="http://javablog.co.uk/2008/01/17/j2me-development-on-os-x-revisited/"&gt;&lt;br /&gt;J2ME Development on OS X, revisited&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-5535494445793089487?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/5535494445793089487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=5535494445793089487' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5535494445793089487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5535494445793089487'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/04/j2me-development-on-osx.html' title='J2ME Development on OSX'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7228321198103793878</id><published>2008-03-27T09:42:00.004+08:00</published><updated>2008-03-27T10:29:51.817+08:00</updated><title type='text'>Syncing your Google Calendar with the Samsung BlackJack using OggSync</title><content type='html'>Firstly, you will need to go to &lt;a href="http://oggsync.com/m/"&gt;OggSync Mobile Install&lt;/a&gt; and download the 2 files there. Most likely you would not need the .NET CF 2.0 SP2 file if you're running WM6 on the BlackJack. Using IE to download, it will automatically ask you whether you wish to install when the download completes, otherwise you will have to call up the File Explorer and go to /My Documents.&lt;br /&gt;&lt;br /&gt;Once installed, OggSync will show up as a new application in the Start menu. When started, you will need to enter the GMail authentication details and complete the initial settings, such as picking the default Google Calendar to sync with and the timezone. After that, you can also set how far in the past and the future you want to sync with 6 months and 5 years given as the maximum respectively.&lt;br /&gt;&lt;br /&gt;With the freeware version, OggSync allows you to sync to only one calendar manually. The Pro version allows multiple calendar syncing and you can set a time interval for it to sync automatically.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7228321198103793878?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7228321198103793878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7228321198103793878' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7228321198103793878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7228321198103793878'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/03/syncing-your-google-calendar-with.html' title='Syncing your Google Calendar with the Samsung BlackJack using OggSync'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-1727422620984192792</id><published>2008-02-14T11:07:00.002+08:00</published><updated>2008-02-14T11:45:19.671+08:00</updated><title type='text'>AMF and BlazeDS</title><content type='html'>Action Message Format (AMF) is a serializing format like XML and JSON. Where the latter two sends formatted text, AMF sends binary data. This allows one to transfer your own domain objects instead of creating a data transfer scheme for XML or JSON. BlazeDS, an &lt;a href="http://www.adobe.com/newsletters/edge/february2008/articles/article2/index.html?trackingid=BSFZP"&gt;open source project from Adobe&lt;/a&gt;,  is the 'enabler' for AMF.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.jamesward.org/wordpress/2007/04/30/ajax-and-flex-data-loading-benchmarks/"&gt;This site&lt;/a&gt; compares the data loading performance between AMF, XML, JSON and a few others. The screenshot shows that AMF took the least time and bandwidth to load the data.&lt;br /&gt;&lt;br /&gt;Sites of Interest:&lt;br /&gt;&lt;a href="http://www.adobe.com/newsletters/edge/february2008/articles/article2/index.html?trackingid=BSFZP"&gt;BlazeDS and what it means for the developer community&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.jamesward.org/wordpress/2007/12/12/blazebench-why-you-want-amf-and-blazeds/"&gt;BlazeBench: Why you want AMF and BlazeDS&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.jamesward.org/wordpress/2007/04/30/ajax-and-flex-data-loading-benchmarks/"&gt;Ajax and Flex Data Loading Benchmarks&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-1727422620984192792?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/1727422620984192792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=1727422620984192792' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1727422620984192792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1727422620984192792'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/02/amf-and-blazeds.html' title='AMF and BlazeDS'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8504814587649032010</id><published>2008-02-13T14:42:00.002+08:00</published><updated>2008-02-13T16:44:46.524+08:00</updated><title type='text'>Flex</title><content type='html'>&lt;div style="text-align: left; font-family: georgia;"&gt;&lt;a href="http://www.flex.org/"&gt;Flex&lt;/a&gt; is a presentation layer in a SWF package using Flash, residing in the client and interacting with the server to obtain data. It is very similar to Wicket, in that you would lay out UI components in a design and add business logic behind the scenes. While Wicket does it with HTML and Java, Flex does it with MXML and ActionScript. Flex is more towards application development than AJAX, but &lt;a href="http://www.quietlyscheming.com/blog/2006/03/06/flex-and-ajax/"&gt;both can use each other&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A Flex interface requires a server API to talk to. &lt;a href="http://learn.adobe.com/wiki/display/Flex/2b.+Code+Files"&gt;This site&lt;/a&gt; shows four ways (ColdFusion, PHP, Java and ASP.NET) to go about it. The data returned by the API would be in XML for ease of use.&lt;br /&gt;&lt;br /&gt;Sites of Interest:&lt;br /&gt;&lt;a href="http://www.onflex.org/ted/2008/01/what-is-flex.php"&gt;What is Flex?&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.quietlyscheming.com/blog/2006/03/06/flex-and-ajax/"&gt;Flex and Ajax: So Happy Together&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.infoq.com/articles/web-flex-port"&gt;From Tags to Riches: Going from Web 1.0 to Flex&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8504814587649032010?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8504814587649032010/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8504814587649032010' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8504814587649032010'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8504814587649032010'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/02/flex.html' title='Flex'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-2776966506149026949</id><published>2008-02-11T11:27:00.000+08:00</published><updated>2008-02-11T12:53:34.105+08:00</updated><title type='text'>Food for thought: Endless learning</title><content type='html'>&lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=221622"&gt;The Mythical 5%&lt;/a&gt; by Bruce Eckel started the brain juices flowing on how to be a better software engineer, following on one of the things the article mentions - listening to podcasts.  It should definitely bring in new ideas, though the question is where to start? Followed some links and trying out &lt;a href="http://javaposse.com/"&gt;The Java Posse&lt;/a&gt; and &lt;a href="http://www.se-radio.net/"&gt;Software Engineering Radio&lt;/a&gt;. Now I need to get my MP3 player working again...&lt;br /&gt;&lt;br /&gt;One of the things I would like to experience would be the pair-programming and working in a team. Being the sole developer has a lot of advantages, such as being able to do with the source code as you will, but it leads to an entrenched viewpoint and blindspots abound.&lt;br /&gt;&lt;br /&gt;There is always plenty to learn, expanding on my Java knowledge would be a good thing. And I would like to delve deep in some other language as a counterweight, exposing me to different coding techniques and styles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-2776966506149026949?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/2776966506149026949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=2776966506149026949' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2776966506149026949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2776966506149026949'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2008/02/food-for-thought-endless-learning.html' title='Food for thought: Endless learning'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-5503722202712657811</id><published>2007-09-07T14:29:00.000+08:00</published><updated>2007-09-07T15:54:24.634+08:00</updated><title type='text'>Spring 2.1 Annotated Dependency Injection</title><content type='html'>&lt;a href="http://blog.interface21.com/main/2007/05/14/annotation-driven-dependency-injection-in-spring-21/"&gt;Annotation-Driven Dependency Injection in Spring 2.1&lt;/a&gt;: This page shows how one can use annotations to entirely inject dependencies. This allows the role of the application context xml file to be minimised, with no bean definitions necessary. Instead the file can be set to an annotation context with scanning of the classes done in the package specified.&lt;br /&gt;&lt;br /&gt;The downside to this is the POJOs are now infected with Spring configuration. For a large project with dozens of files, this would make changes difficult.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-5503722202712657811?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/5503722202712657811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=5503722202712657811' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5503722202712657811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5503722202712657811'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/09/spring-21-annotated-dependency.html' title='Spring 2.1 Annotated Dependency Injection'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6288519731749839904</id><published>2007-09-06T10:38:00.001+08:00</published><updated>2007-09-06T16:16:34.394+08:00</updated><title type='text'>Wicket 1.3</title><content type='html'>Going over the &lt;a href="http://cwiki.apache.org/WICKET/migrate-13.html"&gt;Migrating to Wicket 1.3&lt;/a&gt; page and looking at the API changes which affect the FilmFestival project:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;a href="http://cwiki.apache.org/WICKET/migrate-13.html#Migrate-1.3-FilterinsteadofaServlet"&gt;Using a Filter&lt;/a&gt;&lt;/span&gt;: Change the assignment of ServletContext in the WebApplication subclasses. Change the web.xml listing.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://cwiki.apache.org/WICKET/migrate-13.html#Migrate-1.3-IModelchange"&gt;IModel change&lt;/a&gt;: The FilmFestival's DetachableBlogEntryModel need to extend  some other class as per the migration mapping due to AbstractReadOnlyDetachableModel having been removed. Note the method name changes.&lt;br /&gt;&lt;br /&gt;Interesting bit on CompoundPropertyModel. The project uses CompoundPropertyModels to automatically bind data elements to their page counterparts. As the approach used is different, alteration should not be required.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://cwiki.apache.org/WICKET/migrate-13.html#Migrate-1.3-ValidationChanges"&gt;Validation&lt;/a&gt;: The API for validation has been moved from package wicket.markup.html.form.validation to package org.apache.wicket.validation.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://cwiki.apache.org/WICKET/migrate-13.html#Migrate-1.3-Repeaters"&gt;Repeaters&lt;/a&gt;: This API has been moved from extensions to the core, requiring only a Ctrl-Shift-O to relink the classes affected in the import section.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://cwiki.apache.org/WICKET/migrate-13.html#Migrate-1.3-DatePicker"&gt;DatePicker&lt;/a&gt;: This component has been removed. Alternatives listed need to be used.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://cwiki.apache.org/WICKET/migrate-13.html#Migrate-1.3-Customresourceloading"&gt;Custom resource loading&lt;/a&gt;: Would this allow the html files to be separated from their java counterparts?  The instructions &lt;a href="http://cwiki.apache.org/WICKET/control-where-html-files-are-loaded-from.html"&gt;here&lt;/a&gt; does not seem to use it.&lt;br /&gt;&lt;br /&gt;One of the new features in Wicket 1.3 is &lt;span style="font-weight: bold;"&gt;Enclosure&lt;/span&gt;. Which, as shown &lt;a href="http://www.systemmobile.com/?page_id=253"&gt;here&lt;/a&gt; and &lt;a href="http://cwiki.apache.org/WICKET/wickets-xhtml-tags.html"&gt;here&lt;/a&gt;, is a way of toggling markup visibility for components.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6288519731749839904?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6288519731749839904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6288519731749839904' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6288519731749839904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6288519731749839904'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/09/wicket-13.html' title='Wicket 1.3'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7468196433383709489</id><published>2007-08-29T11:36:00.000+08:00</published><updated>2007-08-29T16:02:21.261+08:00</updated><title type='text'>Installing JIRA, a bug &amp; issue tracker</title><content type='html'>&lt;a href="http://www.atlassian.com/software/jira/docs/latest/install-war.html"&gt;Installing the WAR version&lt;/a&gt;&lt;br /&gt;Obtain and extract the WAR file:&lt;br /&gt;&lt;code&gt;wget http://www.atlassian.com/software/jira/downloads/binary/atlassian-jira-enterprise-3.10.2.tar.gz&lt;br /&gt;gunzip atlassian-jira-enterprise-3.10.2.tar.gz&lt;br /&gt;gtar -xf atlassian-jira-enterprise-3.10.2.tar.gz&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Tomcat is installed through &lt;a href="http://www.blastwave.org/"&gt;Blastwave&lt;/a&gt;. The path is &lt;span style="font-style: italic;"&gt;/opt/csw/share/tomcat5. &lt;/span&gt;Follow the &lt;a href="http://www.atlassian.com/software/jira/docs/latest/servers/tomcat55.html"&gt;Tomcat installation instructions&lt;/a&gt;. The transaction factory in the WAR's &lt;span style="font-style: italic;"&gt;edit-webapp/WEB-INF/classes/entitymanager.xml&lt;/span&gt; is set to Tomcat and does not need to be changed. There are only two settings to be changed for use with &lt;a href="http://www.atlassian.com/software/jira/docs/latest/databases/postgres.html"&gt;PostgreSQL&lt;/a&gt;. Build the distribution and copy from &lt;span style="font-style: italic;"&gt;dist-tomcat/&lt;/span&gt; to the web server.&lt;br /&gt;&lt;br /&gt;Copy and edit the jira.xml file:&lt;br /&gt;&lt;code&gt;cp {WAR}/dist-tomcat/tomcat5.5/jira.xml /opt/csw/share/tomcat5/conf/Catalina/localhost&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The resource should now have &lt;a href="http://jdbc.postgresql.org/doc.html"&gt;four lines&lt;/a&gt;:&lt;br /&gt;&lt;code&gt;username="jira_user"&lt;br /&gt;password="{password}"&lt;br /&gt;driverClassName="org.postgresql.Driver"&lt;br /&gt;url="jdbc:postgresql:jiradb"&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Obtain the JDBC driver for Tomcat and move it to &lt;span style="font-style: italic;"&gt;common/lib&lt;/span&gt;:&lt;br /&gt;&lt;code&gt;wget http://jdbc.postgresql.org/download/postgresql-8.1-410.jdbc3.jar&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Extract the jars to Tomcat's common/lib/ directory:&lt;br /&gt;&lt;code&gt;wget http://www.atlassian.com/software/jira/docs/servers/jars/v1/jira-jars-tomcat5.zip&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Start Tomcat and go do the setup wizard. &lt;a href="http://www.atlassian.com/software/jira/docs/latest/ldap.html"&gt;LDAP authentication&lt;/a&gt; is not tightly coupled therefore you must create JIRA users with the same name as the LDAP users for this to work. A &lt;a href="http://confluence.atlassian.com/display/JIRA/Importing+user+from+LDAP"&gt;bulk-import&lt;/a&gt; of LDAP users can be done if desired.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7468196433383709489?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7468196433383709489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7468196433383709489' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7468196433383709489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7468196433383709489'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/08/installing-jira-bug-issue-tracker.html' title='Installing JIRA, a bug &amp; issue tracker'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-3327964859389875648</id><published>2007-08-29T09:59:00.000+08:00</published><updated>2007-08-29T11:36:11.567+08:00</updated><title type='text'>Grinder 3, a Java load tester</title><content type='html'>The file download is available &lt;a href="http://grinder.sourceforge.net/"&gt;here&lt;/a&gt;. Once downloaded, you can extract it out to any location. It is used through the java command as explained at this &lt;a href="http://www.kvaes.be/web/grinder-load-testing-framework/"&gt;site&lt;/a&gt; and &lt;a href="http://www.wilsonmar.com/grinder3.aspx"&gt;here&lt;/a&gt; as well.&lt;br /&gt;&lt;br /&gt;To get it running as soon as possible, run TCPProxy and set the browser proxy to the port 8001. The proxy will record the actions you take through the browser. Once complete, close the proxy and start the console. Create a grinder.properties from the example given and start the agent. Use the console to start the processes and stop it when you have had enough.&lt;br /&gt;&lt;br /&gt;The results obtained are mostly time statistics. One would have to create or edit a script to obtain more specific details.  Testing against a local webapp using Tomcat revealed a Java heap memory exception in the Tomcat logs. Against the same webapp on a public server, there was no errors in the Grinder logs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-3327964859389875648?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/3327964859389875648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=3327964859389875648' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3327964859389875648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3327964859389875648'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/08/grinder-3-java-load-tester.html' title='Grinder 3, a Java load tester'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7593197991402236623</id><published>2007-08-28T09:09:00.000+08:00</published><updated>2007-08-29T09:59:02.681+08:00</updated><title type='text'>Installing XWiki</title><content type='html'>Before installing the XWiki WAR version listed &lt;a href="http://www.xwiki.org/xwiki/bin/view/AdminGuide/Installation#HInstallingtheXWikiWARmanually"&gt;here&lt;/a&gt;, you'll need to install a servlet container and a relational database, in this case &lt;a href="http://www.xwiki.org/xwiki/bin/view/AdminGuide/InstallationTomcat"&gt;Tomcat&lt;/a&gt; and &lt;a href="http://www.xwiki.org/xwiki/bin/view/AdminGuide/InstallationPostgreSQL"&gt;PostgreSQL&lt;/a&gt;, following the instructions given.&lt;br /&gt;&lt;br /&gt;After configuring XWiki (the concluding step), you will need to import the &lt;a href="http://www.xwiki.org/xwiki/bin/view/AdminGuide/Installation#HInstallingtheDefaultWikiXAR"&gt;default skin&lt;/a&gt; for functionality. It can be downloaded at the &lt;a href="http://www.xwiki.org/xwiki/bin/view/Main/Download#HXWikiEnterprise"&gt;same place&lt;/a&gt; as the WAR file.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.xwiki.org/xwiki/bin/view/AdminGuide/Authentication#HLDAPAuthentication"&gt;LDAP Authentication&lt;/a&gt; is basically straightforward. Replace the values with your own and you are set. LDAP users have to login to XWiki before they have a presence there. XWiki groups have to be assigned as the LDAP groups are not imported in.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7593197991402236623?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7593197991402236623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7593197991402236623' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7593197991402236623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7593197991402236623'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/08/installing-xwiki.html' title='Installing XWiki'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-3788913534434921396</id><published>2007-08-24T09:42:00.000+08:00</published><updated>2007-08-29T09:41:17.997+08:00</updated><title type='text'>Installing Confluence</title><content type='html'>Follow the &lt;a href="http://confluence.atlassian.com/display/DOC/Confluence+Installation+Guide"&gt;install guide here&lt;/a&gt;. Going through the standalone version, ensure that the Java JDK is installed. Obtain the latest Confluence archive, note: 2.5.6 has a &lt;a href="http://jira.atlassian.com/browse/CONF-9195"&gt;bug&lt;/a&gt; that will not allow LDAP authentication to work properly. Also following trying to use the old database with LDAP authentication will open up this &lt;a href="http://jira.atlassian.com/browse/CONF-7582"&gt;bug&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;With Solaris, there is no need for the X11 libraries.  The home directory is where Confluence data will be kept, Confluence itself is in the archive. Go to the  &lt;a href="http://confluence.atlassian.com/display/DOC/Standalone+Setup+Wizard" title="Standalone Setup Wizard"&gt;Confluence Setup Wizard Guide&lt;/a&gt;. Create the admin user.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;LDAP Authentication&lt;/span&gt;&lt;br /&gt;Follow &lt;a href="http://confluence.atlassian.com/display/DOC/Add+LDAP+Integration"&gt;this&lt;/a&gt;. Note Step 3.2. Step 5 must be successful. For Step 6, refer to &lt;a href="http://confluence.atlassian.com/display/DEV/How+to+map+LDAP+Users+and+Groups+to+Confluence+via+Atlassian+User#HowtomapLDAPUsersandGroupstoConfluenceviaAtlassianUser-membershipAttribute"&gt;this&lt;/a&gt; and &lt;a href="http://confluence.atlassian.com/display/DOC/Customising+atlassian-user.xml"&gt;this&lt;/a&gt;. There is a problem with linking LDAP users with their groups, currently both are shown but are not connected. Current solution is to create a Confluence group and use that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-3788913534434921396?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/3788913534434921396/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=3788913534434921396' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3788913534434921396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3788913534434921396'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/08/installing-confluence.html' title='Installing Confluence'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-5523108862993958309</id><published>2007-08-21T11:00:00.000+08:00</published><updated>2007-08-29T09:40:32.270+08:00</updated><title type='text'>LDAP Authentication with TWiki</title><content type='html'>Using &lt;a href="http://twiki.org/cgi-bin/view/Plugins/LdapContrib"&gt;LdapContrib&lt;/a&gt; for transparent authentication. Follow the &lt;a href="http://twiki.org/cgi-bin/view/Plugins/LdapContrib?refreshldap=on"&gt;installation instructions&lt;/a&gt;, first installing the required dependencies either through the script or manually. &lt;a href="http://twiki.org/cgi-bin/view/Support/NewUserPluginRenderLdapCnAsWikiName"&gt;This&lt;/a&gt; explains more on what LdapContrib does. The &lt;a href="http://twiki.org/cgi-bin/view/Plugins/LdapNgPlugin"&gt;LdapNgPlugin&lt;/a&gt; and &lt;a href="http://twiki.org/cgi-bin/view/Plugins/NewUserPlugin"&gt;NewUserPlugin&lt;/a&gt; may be desired.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-5523108862993958309?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/5523108862993958309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=5523108862993958309' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5523108862993958309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5523108862993958309'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/08/ldap-authentication-with-twiki.html' title='LDAP Authentication with TWiki'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7816624522224457159</id><published>2007-08-17T09:52:00.000+08:00</published><updated>2007-08-17T11:51:34.736+08:00</updated><title type='text'>Installing TWiki</title><content type='html'>This post is regarding the installation steps of &lt;a href="http://twiki.org/"&gt;TWiki &lt;/a&gt;on a remote Solaris 11 server. This assumes the installer has root access. The main reference for this post is &lt;a href="http://twiki.org/cgi-bin/view/Codev/SolarisInstallCookbook"&gt;here - Installing TWiki 4.x on Solaris 10&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Create the following (arbitrary) directory structure in the filesystem:&lt;br /&gt;&lt;pre&gt;/apps/twiki-root&lt;br /&gt;/apps/twiki-root/bin&lt;br /&gt;/apps/twiki-root/twiki - &lt;i&gt;A &lt;a href="http://www.openbsd.org/cgi-bin/man.cgi?query=ln"&gt;symlink&lt;/a&gt; to the directory below&lt;/i&gt;&lt;br /&gt;/apps/twiki-root/twiki-4.1.2&lt;br /&gt;/apps/twiki-root/apachemodules&lt;br /&gt;/apps/twiki-root/perlmodules&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Download and unpack the latest TWiki version. Create the LocalLib.cfg file in &lt;code&gt;/apps/twiki-root/twiki/bin&lt;/code&gt;. Modify it to set the twikiLibPath and the path for TWiki related Perl modules:&lt;br /&gt;&lt;pre&gt;$twikiLibPath = "/apps/twiki-root/twiki/lib";&lt;br /&gt;&lt;br /&gt;@localPerlLibPath = ('/apps/twiki-root/perlmodules', '/apps/twiki-root/perlmodules/i86pc-solaris-64int');&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a href="http://twiki.org/cgi-bin/view/Codev/SolarisInstallCookbookPerlModules"&gt;Building CPAN Perl modules on Solaris 10&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;Go over to &lt;a href="http://cpan.org/"&gt;CPAN&lt;/a&gt; and download the CGI::Session and Digest::SHA1 modules. Unpack them into temporary directories and use these commands:&lt;br /&gt;&lt;pre&gt;$ /usr/perl5/bin/perlgcc Makefile.PL [LIB=/apps/twiki-root/perlmodules]&lt;br /&gt;$ make&lt;br /&gt;$ make test&lt;br /&gt;$ make install&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a href="http://www.blastwave.org/"&gt;Blastwave&lt;/a&gt; for GNU &lt;a href="http://www.blastwave.org/packages.php/ggrep"&gt;grep&lt;/a&gt;, &lt;a href="http://www.blastwave.org/packages.php/diffutils"&gt;diff&lt;/a&gt; and &lt;a href="http://www.blastwave.org/packages.php/rcs"&gt;rcs&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;Follow Blastwave installation instructions to enable &lt;code&gt;pkg-get&lt;/code&gt; and install grep, diff and rcs. They will be available in /opt/csw/bin. Create &lt;a href="http://www.openbsd.org/cgi-bin/man.cgi?query=ln"&gt;symlinks&lt;/a&gt; for egrep(-&gt;ggrep), fgrep(-&gt;ggrep) and diff(-&gt;gdiff).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Apache&lt;/h3&gt;&lt;br /&gt;Create the &lt;code&gt;/etc/apache2/httpd.conf&lt;/code&gt; from the example in that directory. Use the &lt;a href="http://twiki.org/cgi-bin/view/TWiki/ApacheConfigGenerator?dir=%2Fapps%2Ftwiki-root%2Ftwiki&amp;allowconf=localhost&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;requireconf=&amp;loginmanager=None&amp;amp;phpinstalled=None"&gt;ApacheConfigGenerator  &lt;/a&gt;to configure a twiki.conf file. Settings used for the generator:&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Enter the full file path to your twiki root directory (mandatory):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;/apps/twiki-root/twiki&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Enter the IP address range or hostnames that will have access to configure - separate with spaces&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;localhost &lt;ip&gt; &lt;ip&gt;&lt;/ip&gt;&lt;/ip&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Enter the list of user names that are allowed to view configure&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Empty&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Enable mod_perl&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Unchecked&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Choose your Login Manager:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;None - No login&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Prevent execution of attached files as PHP scripts if PHP is installed:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;No PHP Installed&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Block direct access to viewing attachments that ends with .htm or .html&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Unchecked&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Block direct access to viewing attachments in Trash web&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;Unchecked&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Append the file to httpd.conf or otherwise have Apache load it. Restart the Apache Web Server:&lt;br /&gt;&lt;pre&gt;svcadm disable apache2&lt;br /&gt;svcadm enable apache2&lt;/pre&gt;&lt;br /&gt;Check &lt;code&gt;/var/svc/log/network- http:apache2.log&lt;/code&gt; to check whether the server is up or it failed to start. Troubleshoot as required.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Browser configuration&lt;/h3&gt;&lt;br /&gt;Go to &lt;code&gt;http://&lt;span style="font-style: italic;"&gt;hostname&lt;/span&gt;/twiki/bin/configure&lt;/code&gt; to continue configuring TWiki. Use &lt;code&gt;/opt/csw/bin&lt;/code&gt; to add to the path. Also use it or create a &lt;a href="http://www.openbsd.org/cgi-bin/man.cgi?query=ln"&gt;symlink&lt;/a&gt; for rcs. Complete the setup.&lt;br /&gt;&lt;br /&gt;Done. More details as forthcoming.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7816624522224457159?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7816624522224457159/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7816624522224457159' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7816624522224457159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7816624522224457159'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/08/installing-twiki.html' title='Installing TWiki'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4403924651973077472</id><published>2007-08-10T09:42:00.000+08:00</published><updated>2007-08-10T10:06:24.506+08:00</updated><title type='text'>LDAP Authentication with SugarCRM</title><content type='html'>Both &lt;a href="http://www.sugarcrm.com/crm/community/sugarcrm-community.html"&gt;SugarCRM&lt;/a&gt; and &lt;a href="http://www.openldap.org/"&gt;LDAP&lt;/a&gt; are installed. LDAP is to be used to authenticate users in SugarCRM.&lt;br /&gt;&lt;br /&gt;Login to SugarCRM as admin. Click on the 'Admin' button at the top of the page and then 'System Settings' in the main page.&lt;br /&gt;&lt;br /&gt;Set 'Enable LDAP'. The default LDAP server and port number are &lt;span style="font-style: italic;"&gt;localhost&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;389&lt;/span&gt; respectively. Change as required. The base dn is the location where the search for users begin, in this case &lt;span style="font-style: italic;"&gt;dc=nodomain&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;For the bind attribute, disregarding the example text, it should be &lt;span style="font-style: italic;"&gt;dn&lt;/span&gt;. More information &lt;a href="http://www.sugarcrm.com/forums/showthread.php?t=20960"&gt;here&lt;/a&gt;. The login attribute is the username to be used. Any attribute can be used (e.g &lt;span style="font-style: italic;"&gt;uid&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;sn&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;cn&lt;/span&gt;). An important thing to note is with 'Auto Create Users' set, a change in login attribute will create new users with that attribute as the username. If 'Auto Create Users' is not set, authentication will fail as the user may be present in LDAP but not in the SugarCRM database due to the username.&lt;br /&gt;&lt;br /&gt;Authenticated user and password is the LDAP account to be used for searching. The 'Auto Create Users', as mentioned before, creates new users from their LDAP information if they are not present in SugarCRM. The encryption key may be left empty.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4403924651973077472?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4403924651973077472/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4403924651973077472' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4403924651973077472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4403924651973077472'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/08/ldap-authentication-with-sugarcrm.html' title='LDAP Authentication with SugarCRM'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-1978750876255923717</id><published>2007-08-07T11:13:00.000+08:00</published><updated>2007-08-10T14:14:29.009+08:00</updated><title type='text'>svnsync: A Subversion Mirror</title><content type='html'>The steps to mirror a subversion repository are detailed &lt;a href="http://bob.pythonmac.org/archives/2006/09/14/svnsync-mirror-your-svn-repository/"&gt; here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;My take on those steps:&lt;br /&gt;&lt;pre class="literal-block"&gt;$ svnadmin create /var/svn/backup&lt;br /&gt;$ echo '#!/bin/sh' &gt; /var/svn/backup/hooks/pre-revprop-change&lt;br /&gt;$ chmod +x /var/svn/backup/hooks/pre-revprop-change&lt;br /&gt;$ svnsync init file:///var/svn/backup svn+ssh://[username]@svn.sixpaq.com/home/[username]/svn/projects&lt;br /&gt;$ svnsync sync file:///var/svn/backup&lt;/pre&gt;Other places of interest are &lt;a href="https://www.opends.org/wiki//page/MirroringASubversionRepository"&gt;here&lt;/a&gt;, &lt;a href="http://blog.notreally.org/articles/2006/11/30/setting-up-a-subversion-mirror-repository-using-svnsync/"&gt;here&lt;/a&gt; and &lt;a href="http://blog.notreally.org/articles/2006/12/13/more-on-setting-a-subversion-mirror-repository/"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-1978750876255923717?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/1978750876255923717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=1978750876255923717' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1978750876255923717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1978750876255923717'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/08/svnsync-subversion-mirror.html' title='svnsync: A Subversion Mirror'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8421853445567395694</id><published>2007-07-18T12:32:00.000+08:00</published><updated>2007-07-18T17:23:30.879+08:00</updated><title type='text'>Python strings (vs. Java strings)</title><content type='html'>Python strings are more or less similar to Java strings. A difference is the formatting of Python strings are done in the strings themselves. Also Python strings have more methods than their Java counterparts.&lt;br /&gt;&lt;br /&gt;Methods:&lt;br /&gt;The Python methods, &lt;span style="font-style: italic;"&gt;find &lt;/span&gt;(the same as &lt;span style="font-style: italic;"&gt;index&lt;/span&gt;) and &lt;span style="font-style: italic;"&gt;rfind &lt;/span&gt;(&lt;span style="font-style: italic;"&gt;rindex&lt;/span&gt;)  have their Java opposite, &lt;span style="font-style: italic;"&gt;indexOf &lt;/span&gt;and &lt;span style="font-style: italic;"&gt;lastIndexOf&lt;/span&gt;. So does &lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;lower&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;upper &lt;/span&gt;in the Java methods &lt;span style="font-style: italic;"&gt;toLowerCase &lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;and &lt;span style="font-style: italic;"&gt;toUpperCase&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;.&lt;span style="font-style: italic;"&gt; split&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;replace, startsWith&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;endsWith&lt;/span&gt; are common to Python and Java.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;join&lt;/span&gt;, the opposite of &lt;span style="font-style: italic;"&gt;split&lt;/span&gt;, does not have a Java equivalent. The &lt;span style="font-style: italic;"&gt;join &lt;/span&gt;method concatenates the members of a string sequence together with a specified divider. Neither do these methods: &lt;span style="font-style: italic;"&gt;count&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;isalpha&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;isalnum&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;isdigit&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;islower&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;capitalize&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;isupper&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;title&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;istitle&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;swapcase&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;expandtabs&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;translate&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Formatting:&lt;br /&gt;The string formatting operator, the percent (%) sign, does all the work as an example from the &lt;span style="font-style: italic;"&gt;Beginning Python: From Novice to Professional&lt;/span&gt; book shows:&lt;br /&gt;&lt;pre&gt;&gt;&gt;&gt; format = "Hello, %s. %s enough for ya?"&lt;br /&gt;&gt;&gt;&gt; values = ('world', 'Hot')&lt;br /&gt;&gt;&gt;&gt; print format % values&lt;br /&gt;Hello, world. Hot enough for ya?&lt;br /&gt;&lt;/pre&gt;Templates strings are another way of formatting. Basically these are strings with variables that are substituted with the actual value. Below are two examples from the book:&lt;br /&gt;&lt;pre&gt;&gt;&gt;&gt; from string import Template&lt;br /&gt;&gt;&gt;&gt; s = Template('$x, glorious $x!')&lt;br /&gt;&gt;&gt;&gt; s.substitute(x='slurm')&lt;br /&gt;'slurm, glorious slurm!'&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&gt;&gt;&gt; s = Template("It's ${x}tastic!")&lt;br /&gt;&gt;&gt;&gt; s.substitute(x='slurm')&lt;br /&gt;"It's slurmtastic!"&lt;br /&gt;&lt;/pre&gt;A third example uses a dictionary for substitution with value-name pairs:&lt;br /&gt;&lt;pre&gt;&gt;&gt;&gt; s = Template('A $thing must never $action.')&lt;br /&gt;&gt;&gt;&gt; d = {}&lt;br /&gt;&gt;&gt;&gt; d['thing'] = 'gentleman'&lt;br /&gt;&gt;&gt;&gt; d['action'] = 'show his socks'&lt;br /&gt;&gt;&gt;&gt; s.substitute(d)&lt;br /&gt;'A gentleman must never show his socks.'&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8421853445567395694?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8421853445567395694/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8421853445567395694' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8421853445567395694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8421853445567395694'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/07/python-strings-vs-java-strings.html' title='Python strings (vs. Java strings)'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6330708605642143899</id><published>2007-07-04T08:42:00.000+08:00</published><updated>2007-07-04T12:06:24.138+08:00</updated><title type='text'>Creating a Drupal module</title><content type='html'>First, went to the &lt;a href="http://drupal.org/node/508"&gt;module developer's guide page&lt;/a&gt; and did the &lt;a href="http://drupal.org/node/82920"&gt;tutorial for Drupal 5.x&lt;/a&gt;. The block module in the tutorial, when completed, is full of code that integrates the module into the Drupal CMS. We don't need much of that code for now.&lt;br /&gt;&lt;br /&gt;We want a quick and dirty email notifier module. First we create the info file that contains information which the CMS will display. The module's name is &lt;span style="font-weight: bold;"&gt;Messenger&lt;/span&gt; so the file will be &lt;span style="font-style: italic;"&gt;messenger.info&lt;/span&gt;:&lt;br /&gt;&lt;pre&gt;; $Id$&lt;br /&gt;name = Messenger&lt;br /&gt;description = "Sends out an email whenever new content has been created."&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then we have the module file, messenger.module. We add the &lt;span style="font-style: italic;"&gt;hook_help&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;hook_perm&lt;/span&gt; functions from the tutorial. Through the &lt;a href="http://api.drupal.org/api/5/group/hooks"&gt;Hooks API&lt;/a&gt;, we use the &lt;span style="font-style: italic;"&gt;hook_nodeapi&lt;/span&gt; function which will run itself whenever there is node activity. This function is where we put in the mail command:&lt;br /&gt;&lt;pre&gt;function messenger_nodeapi(&amp;$node, $op, $a3 = NULL, $a4 = NULL)&lt;br /&gt;{&lt;br /&gt; switch($op)&lt;br /&gt; {&lt;br /&gt;   case 'insert':&lt;br /&gt;     $query = "SELECT mail FROM users ".&lt;br /&gt;              "WHERE name = 'admin'";&lt;br /&gt;     $queryResult =  db_query($query);&lt;br /&gt;&lt;br /&gt;     $user = db_fetch_object($queryResult);&lt;br /&gt;   &lt;br /&gt;     $to = $user-&gt;mail;&lt;br /&gt;     $subject = "New content available!";&lt;br /&gt;     $body = "Someone's been adding new content! To ensure it's nothing illegal, please go check it out.";&lt;br /&gt;     $from = "drupalcares@whocares.com";&lt;br /&gt;     $headers = array();&lt;br /&gt;&lt;br /&gt;     $mail_success = drupal_mail('messenger', $to, $subject, $body, $from);&lt;br /&gt;     if(!$mail_success)&lt;br /&gt;     {&lt;br /&gt;       drupal_set_message(t('There has been an error.\\nTo: '.$to.'\/nSubject: '.$subject.'\rBody: '.$body.'\nFrom: '.$from.'\nHeaders: '.$headers));&lt;br /&gt;     }&lt;br /&gt;     else&lt;br /&gt;     {&lt;br /&gt;       drupal_set_message(t('A mail has been sent to the admin. Prepare yourself! :)'));&lt;br /&gt;     }&lt;br /&gt;     drupal_set_message(t('Yay, you just inserted something! :)'));&lt;br /&gt;     break;&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;One thing to check is whether sendmail is available on the Ubuntu system. If sendmail is not working then the module will not work.&lt;br /&gt;&lt;br /&gt;The module is functional now. Further improvements can be done; sending the mail to more than one admin or even to users, restricting the notification to just pages or blog entries and making it configurable through the CMS.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6330708605642143899?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6330708605642143899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6330708605642143899' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6330708605642143899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6330708605642143899'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/07/creating-drupal-module.html' title='Creating a Drupal module'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8694679049767975645</id><published>2007-06-26T13:02:00.000+08:00</published><updated>2007-06-26T13:49:04.226+08:00</updated><title type='text'>Drupal Modules</title><content type='html'>&lt;a href="http://drupal.org/"&gt;Drupal&lt;/a&gt; requires a few modules before it can be truly functioning to one's expectation. The three sites listed below are more than enough for the beginner. As it is, some of the modules are only relevant if the website to be built is of a particular type - community, commercial, blog, etc. That said, the one module that must be installed would be the WYSIWYG editor. The default Drupal content creation way is to type in the page wholesale with all the markup which is a pain!&lt;br /&gt;&lt;br /&gt;Modules:&lt;br /&gt;&lt;a href="http://www.nikoport.com/2007/03/22/top-10-drupal-modules/"&gt;Top 10 Drupal modules&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.nicklewis.org/node/766"&gt;10 Drupal Modules You Can't Live Without&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.lullabot.com/audiocast/drupal_podcast_no_40_top_40_projects"&gt;Drupal Podcast No. 40: Top 40 Projects&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;WYSIWYG Editor:&lt;br /&gt;&lt;a href="http://drupal.org/project/tinymce"&gt;TinyMCE WYSIWYG Editor&lt;/a&gt;&lt;br /&gt;&lt;a href="http://drupal.org/project/widgeditor"&gt;widgEditor - A WYSIWYG editor&lt;/a&gt;&lt;br /&gt;&lt;a href="http://drupal.org/project/fckeditor"&gt;FCKeditor&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8694679049767975645?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8694679049767975645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8694679049767975645' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8694679049767975645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8694679049767975645'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/06/drupal-modules.html' title='Drupal Modules'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7015648298299397062</id><published>2007-06-22T09:39:00.000+08:00</published><updated>2007-06-22T09:46:56.603+08:00</updated><title type='text'>PHP HTTP Authentication using database with PEAR</title><content type='html'>With Ubuntu 7.04 (Feisty Fawn) and a Synaptic-installation of php5, you'll have to install the Auth_HTTP package as in the book and then the DB package.&lt;br /&gt;&lt;br /&gt;To obtain data read from the database, must use the &lt;code&gt;getAuthData("column_name")&lt;/code&gt; method on the Auth_HTTP object.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7015648298299397062?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7015648298299397062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7015648298299397062' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7015648298299397062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7015648298299397062'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/06/php-http-authentication-using-database.html' title='PHP HTTP Authentication using database with PEAR'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6944428039699619431</id><published>2007-06-21T09:17:00.000+08:00</published><updated>2007-06-21T12:05:05.916+08:00</updated><title type='text'>PHP HTTP Authentication</title><content type='html'>The HTTP Authentication for PHP comes in two versions, “Basic” and “Digest”.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Basic sends the username and password across the net in plain text.&lt;/li&gt;&lt;li&gt;Digest uses some clever one-way encryption techniques (eg. MD5 or SHA1) to prove that both client and server are exactly who they say they are without actually sending the password at all (in fact the server doesn't even need to store the password itself).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;A problem with HTTP Authentication is that there is no way to easily logout, in fact there is no support for logging out. The browser can access the restricted material until such time that the cached credentials are flushed. This usually happens when the browser is closed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6944428039699619431?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6944428039699619431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6944428039699619431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6944428039699619431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6944428039699619431'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/06/php-http-authentication.html' title='PHP HTTP Authentication'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7645847804746015719</id><published>2007-06-15T09:14:00.000+08:00</published><updated>2007-06-15T11:01:40.763+08:00</updated><title type='text'>Beginning PHP and MySQL 5 - Chapters 1-7</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Ch 1 - An Introduction  to PHP&lt;/span&gt;&lt;br /&gt;Basically the history of PHP and why you should use it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ch 2 - Installing and Configuring Apache and PHP&lt;/span&gt;&lt;br /&gt;Useful in getting started up. There are a lot of configuration options listed out. Using default values so skipped over it for now.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ch 3 - PHP Basics&lt;/span&gt;&lt;br /&gt;Learned the syntax that are available, quite a few including a short form version. Went through comments, outputting to html, datatypes, variables and constants, expessions and control structures like if, if-else and switch.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ch 4 - Functions&lt;/span&gt;&lt;br /&gt;All about functions, the prototype for a function is similar to a method:&lt;br /&gt;&lt;pre&gt;function function_name(parameters)&lt;br /&gt;{&lt;br /&gt;   function-body&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;There is no return type required. If needed, it can be added to the body.&lt;br /&gt;&lt;br /&gt;Variable functions are functions which are evaluated at execution time to retrieve their names:&lt;br /&gt;&lt;pre&gt;$function()&lt;/pre&gt;Given a URL parameter, this allows one to bypass the tedious if statement in order to know which function to call:&lt;br /&gt;&lt;pre&gt;if($trigger == "retrieveUser")&lt;br /&gt;{&lt;br /&gt;   retrieveUser($rowid);&lt;br /&gt;}&lt;br /&gt;else if($trigger == "retrieveNews")&lt;br /&gt;{&lt;br /&gt;   retrieveNews($rowid);&lt;br /&gt;}&lt;br /&gt;else if($trigger == "retrieveWeather")&lt;br /&gt;{&lt;br /&gt;   retrieveWeather($rowid);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;to the much more compact:&lt;br /&gt;&lt;pre&gt;$trigger($rowid);&lt;br /&gt;&lt;/pre&gt;There are security risks in using this so care must be taken.&lt;br /&gt;&lt;br /&gt;Reuseable functions can be stored in a function library and called up by:&lt;br /&gt;&lt;pre&gt;include("function.library.php");&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Ch 5 - Arrays&lt;/span&gt;&lt;br /&gt;Of note is the natural sorting function, &lt;code&gt;natsort()&lt;/code&gt;, which sorts (10, 1, 20, 2) to (1, 2, 10, 20) instead of (1, 10, 2, 20).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ch 6 - Object-Oriented PHP&lt;/span&gt;&lt;br /&gt;Normal OO stuff that can be found in C or Java. The Properties feature in PHP can be used to extend the class by adding in new properties. A potential gotcha for constructors is that they do not call the parent constructor automatically.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ch 7 - Advanced OOP Features&lt;/span&gt;&lt;br /&gt;Again more of the same. However there are OOP features that are not supported such constructor, method and operator overloading. There is a section on reflection, showing how to obtain the class type, methods and parameters.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7645847804746015719?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7645847804746015719/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7645847804746015719' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7645847804746015719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7645847804746015719'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/06/beginning-php-and-mysql-5-chapters-1-7.html' title='Beginning PHP and MySQL 5 - Chapters 1-7'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-3488437075518980969</id><published>2007-06-13T13:21:00.000+08:00</published><updated>2007-06-13T15:22:21.584+08:00</updated><title type='text'>Initial thoughts on PHP</title><content type='html'>Learning PHP through a book entitled &lt;span style="font-style:italic;"&gt;&lt;span style="font-weight:bold;"&gt;Beginning PHP and MySQL 5: From Novice to Professional, Second Edition&lt;/span&gt;&lt;/span&gt; by &lt;span style="font-style:italic;"&gt;W. Jason Gilmore&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;PHP is a loosely-typed language due to its origin as a web counter script. This is inherent in the quick and dirty way it does things, one can put in a variable and assign and reassign it to various data types like strings, integers and floats. There is no need for declarations and type-casting, though it is available. Coming from a Java background, that is very off-putting. Acclimation would be easy but care must be taken to prevent any bad programming habits from creeping in.&lt;br /&gt;&lt;br /&gt;The OOP aspect of PHP is a mix of C and Java coding styles. In that respect, it is pretty conventional and a Java programmer can take easily to it. Relatively simple websites should be easy to prototype quickly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-3488437075518980969?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/3488437075518980969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=3488437075518980969' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3488437075518980969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3488437075518980969'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/06/initial-thoughts-on-php.html' title='Initial thoughts on PHP'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-144310986533808955</id><published>2007-06-07T13:59:00.000+08:00</published><updated>2007-06-13T13:21:47.171+08:00</updated><title type='text'>Installing CruiseControl - a continuous integration framework</title><content type='html'>The first step in installing CruiseControl (CC) is going to the SourceForge site and &lt;a href="http://cruisecontrol.sourceforge.net/download.html"&gt;downloading&lt;/a&gt; the distribution. There are two flavors, a binary and a source distribution. You should choose the binary distribution as it is a trimmed version of the source distribution and is much simpler to use. After the download, extract the file to where you want to place it.&lt;br /&gt;&lt;br /&gt;From here, you will want to follow the getting started guides for the &lt;a href="http://cruisecontrol.sourceforge.net/gettingstartedbindist.html"&gt;binary&lt;/a&gt; and &lt;a href="http://cruisecontrol.sourceforge.net/gettingstartedsourcedist.html"&gt;source&lt;/a&gt; distributions in order to set up CruiseControl. The binary distribution lets you run it 'out of the box' and you can see how a functional CC is supposed to work. Once you have the hang of it, you can try out putting your own project under CC. Using the guide for the source distribution, under the "Running the Build Loop" section, you can specify a place to store all your work.&lt;br /&gt;&lt;br /&gt;Now the binary distribution sets the root of  the CC directory to where the sh/bat executive file is called from. The requirement is that CC's lib and dist directories must be there. So the default is to call cruisecontrol.sh from the extraction place, that will also bind the project storage to be there. If you call the sh file from the specified place in the previous paragraph, CC will complain about not finding the lib and dist directories. The solution is to edit cruisecontrol.sh and hardcode the CCDIR to the extraction place, then call it from the project storage. Note that the binary distribution uses a projects directory instead of a checkout directory.&lt;br /&gt;&lt;br /&gt;After that, follow the guide in creating config.xml and build-&lt;project&gt;.xml, making changes as necessary. CC makes use of the Ant build tool so all the project compiling, testing and archiving are done using that. This &lt;a href="http://www.oracle.com/technology/products/jdev/tips/mills/cruisecontrol/jdev_svn_cc.html"&gt;site&lt;/a&gt; tells you how to make use of SVN in Ant instead of CVS.&lt;br /&gt;&lt;br /&gt;Links:&lt;br /&gt;&lt;/project&gt;&lt;ul&gt;&lt;li&gt;&lt;project&gt;&lt;a href="http://cruisecontrol.sourceforge.net/index.html"&gt;CruiseControl&lt;/a&gt;&lt;/project&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://cruisecontrol.sourceforge.net/gettingstartedbindist.html"&gt;Getting Started with the Binary Distribution&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://cruisecontrol.sourceforge.net/gettingstartedsourcedist.html"&gt;Getting Started with the Source Distribution&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.oracle.com/technology/products/jdev/tips/mills/cruisecontrol/jdev_svn_cc.html"&gt;JDeveloper, Subversion and Cruise Control&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-144310986533808955?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/144310986533808955/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=144310986533808955' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/144310986533808955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/144310986533808955'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/06/installing-cruisecontrol-continuous.html' title='Installing CruiseControl - a continuous integration framework'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-289024822304719705</id><published>2007-06-06T10:22:00.000+08:00</published><updated>2007-06-06T13:14:05.323+08:00</updated><title type='text'>Continuous Integration</title><content type='html'>Continuous Integration (CI) is a software development practice of having team members integrate their work into the project frequently. Every integration is automatically built and tested so integration errors can be flushed out.&lt;br /&gt;&lt;br /&gt;From &lt;a href="http://www.martinfowler.com/articles/continuousIntegration.html"&gt;Martin Fowler's article on CI&lt;/a&gt;, the practices to follow are:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Maintain a Single Source Repository&lt;/li&gt;&lt;li&gt;Automate the Build&lt;/li&gt;&lt;li&gt;Make Your Build Self-Testing&lt;/li&gt;&lt;li&gt;Everyone Commits Every Day&lt;/li&gt;&lt;li&gt;Every Commit Should Build the Mainline on an Integration Machine&lt;/li&gt;&lt;li&gt;Keep the Build Fast&lt;/li&gt;&lt;li&gt;Test in a Clone of the Production Environment&lt;/li&gt;&lt;li&gt;Make it Easy for Anyone to Get the Latest Executable&lt;/li&gt;&lt;li&gt;Everyone can see what's happening&lt;/li&gt;&lt;li&gt;Automate Deployment&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Current practice at the moment only make use of steps 1 and 2. With step 2, though an Ant build script is present, the Eclipse IDE's automatic build is favored.&lt;br /&gt;&lt;br /&gt;Step 3 - Tests are coded but currently they are run by hand, not in conjunction with the build. Step 4 - This is not adhered to, usually committing is done when a large task has been completed.&lt;br /&gt;&lt;br /&gt;Steps 5, 6 and 7 are not relevant with the current practice.&lt;br /&gt;&lt;br /&gt;Step 8 - Current practice is to ask developer for the latest code, use the source repository to transfer the code then build it. If the code is transferred to a new machine, custom settings have to be supplied before it can be built. Generally a lot of hassle and potential pitfalls.&lt;br /&gt;&lt;br /&gt;Step 9 - Only the developer knows what's happening, anyone else has to be informed by that person.&lt;br /&gt;&lt;br /&gt;Step 10 - The Ant build script has a deployment task. However that task only deals with production deployment which is set to a particular server and is not suitable for testing.&lt;br /&gt;&lt;br /&gt;CI is supposed to lessen integration impact and allow for better communication between team members who are working on a project. Being a development team of one, there are no major issues. Anything that occurs is the result of that single developer and must subsequently be resolved by that person. However that will change as the team grows.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-289024822304719705?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/289024822304719705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=289024822304719705' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/289024822304719705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/289024822304719705'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/06/continuous-integration.html' title='Continuous Integration'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8847549321585186371</id><published>2007-04-25T15:33:00.000+08:00</published><updated>2007-04-26T10:38:34.241+08:00</updated><title type='text'>Wicket (vs. Tapestry)</title><content type='html'>Wicket, as with Tapestry, is a view technology that uses plain HTML and Java code to render web sites. However where with Tapestry you have the controlling logic split between the Java code and html/page files, Wicket thrusts all logic into the Java code and use the html pages only to define the position of its components.&lt;br /&gt;&lt;br /&gt;In addition, there is no xml configuration needed aside from the inclusion of the Wicket servlet into the web application.  Any configuration is done in Java code. As such the components in Wicket can be reused and also inherit from other components, normal Java behaviour.&lt;br /&gt;&lt;br /&gt;After trying Wicket for a few days, it is very much easier to use than Tapestry. The split logic in Tapestry forces one to constantly refer to the html pages for what components are used and their settings and the Java for the logic behaviour. Keeping all the logic in Java enables one to have a clearer picture on what the components are and what they do, and the html pages only need their wicket ids to function.&lt;br /&gt;&lt;br /&gt;Another thing is the strict enforcement of wicket ids referencing their respective components. If one has a wicket id that is not referencing a component somewhere in the Java code, the webapp cannot render it and gives an error page. Similarly for a component that tries to add itself to a page without an id.&lt;br /&gt;&lt;br /&gt;Shifting from Tapestry, one had to change their coding mindset from a single Java file for a html page. Wicket also requires that, however a base page can be defined and, taking advantage of inheritance, be extended by other pages.  Components in one page can be reused in another and so on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8847549321585186371?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8847549321585186371/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8847549321585186371' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8847549321585186371'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8847549321585186371'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/04/wicket-vs-tapestry.html' title='Wicket (vs. Tapestry)'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-1378790059380669709</id><published>2007-04-10T16:31:00.000+08:00</published><updated>2007-04-26T10:47:24.619+08:00</updated><title type='text'>Maven</title><content type='html'>&lt;a href="http://maven.apache.org/"&gt;http://maven.apache.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Maven can be run straight out of the archive, once the systempath variables are set. Following the 5 minutes guide, I created a 'Hello World' app, compiled, tested and finally packaged it into a jar. Going further, using 'mvn eclipse:eclipse' allowed it to be imported into the Eclipse IDE. There is also a plugin available for tight integration between Maven and Eclipse.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Dependency management is one prime reason for using Maven. The dependencies are downloaded from a remote repository and stored in a local repository that Maven creates. So for several projects, there will be only be one dependency copy. The default remote repository can be changed to an internal repository that will house a private copy of dependencies.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;In regards to Ant, Maven makes for a more standardized build process, with little or no configuration needed to start creating, building and testing projects. It provides a common directory layout for each Maven project, easing orientation.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre id="comment_text_0"&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-1378790059380669709?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/1378790059380669709/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=1378790059380669709' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1378790059380669709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1378790059380669709'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/04/maven.html' title='Maven'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7718385835968898714</id><published>2007-02-21T08:51:00.000+08:00</published><updated>2007-02-21T09:56:03.931+08:00</updated><title type='text'>Repository Pattern in lieu of DAO Pattern</title><content type='html'>&lt;h3 style="font-weight: normal; font-style: italic;" class="post-title"&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;&lt;/span&gt;&lt;/h3&gt;&lt;a href="http://debasishg.blogspot.com/2007/02/domain-driven-design-inject.html"&gt;Domain Driven Design - Inject Repositories, not DAOs in Domain Entities&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Instead of the usual domain-DAO-database, a Repository is added so that it becomes domain-Repository-DAO-database.&lt;br /&gt;&lt;br /&gt;The Repository contains domain-centric methods and uses the DAO to interact with the database.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://debasishg.blogspot.com/2007/02/domain-driven-design-use-orm-backed.html"&gt;Domain Driven Design : Use ORM backed Repository for Transparent Data Access&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;With Hibernate or JPA taking care of persistence and simplifying the DAO, the Repository can interact directly with the ORM and drop the DAO. So it becomes domain-Repository-Hibernate/JPA.&lt;br /&gt;&lt;br /&gt;The link gives a general implementation of the Repository, which adopts a Bridge pattern to separate the abstraction (which will be exposed to the client code) and the implementation (which can swapped between Hibernate or JPA). It shows how the client Repository can extend from the general implementation.&lt;br /&gt;&lt;br /&gt;The design is attractive, with the general implementation available to be used in any project. However it requires more thought to use it and and the unfamiliarity requires that more groundwork needs to be done before one can be proficient in it.&lt;br /&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7718385835968898714?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7718385835968898714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7718385835968898714' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7718385835968898714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7718385835968898714'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/02/repository-pattern-in-lieu-of-dao.html' title='Repository Pattern in lieu of DAO Pattern'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7736668293500994635</id><published>2007-02-20T16:27:00.000+08:00</published><updated>2007-02-20T17:18:28.579+08:00</updated><title type='text'>Ubuntu 6.10, Edgy Eft</title><content type='html'>Downloaded and installed the latest version of Ubuntu, 6.10 - Edgy Eft. The ISO is a combination Live CD and installation CD, it loads up the Live CD first and offers an option to install.&lt;br /&gt;&lt;br /&gt;Installation is pretty much the same as the procedure listed in the Apress book, "Beginning Ubuntu Linux". After installation, there were a lot of updates to download and install.&lt;br /&gt;&lt;br /&gt;Ubuntu comes internet-ready, provided one has an active connection. Firefox is available and browsing can be done after installation.&lt;br /&gt;&lt;br /&gt;Playing media files, music and video, however means downloading and installing codecs. The Apress book has a section on it, also there is a &lt;a href="http://ubuntuguide.org/wiki/Ubuntu_Edgy"&gt;unofficial Wiki guide&lt;/a&gt; that lists a lot of how-to stuff, including codec installation. Following the guide requires one to be familiar with the command prompt though.&lt;br /&gt;&lt;br /&gt;NTFS drives can be mounted to the filesystem in a read-only capacity. One would need to use FAT drives to share data between Windows and Linux.&lt;br /&gt;&lt;br /&gt;The GUI offers more than enough configuration managers that the command prompt can be ignored for the basic user.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7736668293500994635?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7736668293500994635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7736668293500994635' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7736668293500994635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7736668293500994635'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/02/ubuntu-610-edgy-eft.html' title='Ubuntu 6.10, Edgy Eft'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-2676802930256726925</id><published>2007-02-15T12:50:00.000+08:00</published><updated>2007-02-16T17:05:14.733+08:00</updated><title type='text'>Spring-JPA-Tomcat</title><content type='html'>Created an Eclipse project that follows the '&lt;span style="font-style: italic;"&gt;Introduction to Spring 2 and JPA&lt;/span&gt;' pdf. This entails creating POJOs, the business objects of the application, which in this case are the &lt;span style="font-style: italic;"&gt;Employee&lt;/span&gt; class and the &lt;span style="font-style: italic;"&gt;Address &lt;/span&gt;class. The POJOs do not contain any business logic, possessing only their data fields and the associated getters and setters. Two constructors are added, a no-arg constructor and another constructor that sets all the fields with data.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-style: italic;"&gt;POJOUnitTest &lt;/span&gt;class, a Junit test case, is coded to unit test the &lt;span style="font-style: italic;"&gt;Employee &lt;/span&gt;and &lt;span style="font-style: italic;"&gt;Address &lt;/span&gt;classes. Their objects are created, inserted with data (via setter methods and also constructor) and then the data is verified in the test.&lt;br /&gt;&lt;br /&gt;A service layer containing the business logic to use these POJOs is visualized in the &lt;span style="font-style: italic;"&gt;EmployeeService &lt;/span&gt;interface, which contains abstract methods for dealing with the Employee class.&lt;br /&gt;&lt;br /&gt;Up to now, it's been plain Java coding. Spring and JPA comes into play when one needs to add database support. JPA annotations are added to the POJOs, at the class and field names, to establish the mapping between objects and database counterparts. Spring's JPA support enables one to use its DAO API to code the implementation class which extends &lt;span style="font-style: italic;"&gt;JpaDaoSupport &lt;/span&gt;and implements the &lt;span style="font-style: italic;"&gt;EmployeeService &lt;/span&gt;interface, called &lt;span style="font-style: italic;"&gt;EmployeeDAO&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Now we use Spring to string these POJOs up as beans in &lt;span style="font-style: italic;"&gt;dwspring-service.xml&lt;/span&gt;. Here  the provider is changed from TopLink to Hibernate and a database change to MySQL by modifying the &lt;span style="font-style: italic;"&gt;entityManagerFactory &lt;/span&gt;bean's properties as shown below:&lt;br /&gt;&lt;span style="font-size:100%;"&gt;From:&lt;/span&gt;&lt;br /&gt;&lt;code&gt;property name="jpaVendorAdapter"&lt;br /&gt;bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter"&lt;br /&gt;property name="databasePlatform"&lt;br /&gt;value="oracle.toplink.essentials.platform.database.HSQLPlatform"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;To:&lt;br /&gt;&lt;code&gt;property name="jpaVendorAdapter"&lt;br /&gt;   bean class="&lt;span style="font-weight: bold;"&gt;org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter&lt;/span&gt;"&lt;br /&gt;property name="databasePlatform"&lt;br /&gt;   value="&lt;span style="font-weight: bold;"&gt;org.hibernate.dialect.MySQLDialect&lt;/span&gt;"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Needless to say, the properties of the &lt;span style="font-style: italic;"&gt;dataSource &lt;/span&gt;bean (&lt;span style="font-style: italic;"&gt;driverClassName&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;url&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;username&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;password&lt;/span&gt;) need to be changed to reflect the use of the MySQL database.&lt;br /&gt;&lt;br /&gt;Another test, an integration test this time, verifies that the &lt;span style="font-style: italic;"&gt;EmployeeDAO &lt;/span&gt;implementation of &lt;span style="font-style: italic;"&gt;EmployeeService &lt;/span&gt;works against an actual database. The classname is &lt;span style="font-style: italic;"&gt;EmployeeServiceImplementationTest &lt;/span&gt;and it extends &lt;span style="font-style: italic;"&gt;AbstractJpaTests&lt;/span&gt;. This allows implementation of the &lt;span style="font-style: italic;"&gt;getConfigLocations&lt;/span&gt;() method, where one or more beans configuration files can be parsed by the Spring engine. This enables automatic dependency injection; when Spring loads the  &lt;span style="font-style: italic;"&gt;EmployeeServiceImplementationTest &lt;/span&gt;class, it will discover an unfulfilled dependency - a property of type &lt;span style="font-style: italic;"&gt;EmployeeService&lt;/span&gt;. The engine looks through the &lt;span style="font-style: italic;"&gt;dwspring2-service.xml&lt;/span&gt; file for a configured bean of type &lt;span style="font-style: italic;"&gt;EmployeeService &lt;/span&gt;and injects it via the &lt;span style="font-style: italic;"&gt;setEmployeeService&lt;/span&gt;() method. The relevant code is below:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;public class EmployeeServiceIntegrationTest extends AbstractJpaTests {&lt;br /&gt;   private EmployeeService employeeService;&lt;br /&gt;   private long JoeSmithId = 99999;&lt;br /&gt;   public void setEmployeeService(EmployeeService employeeService) {&lt;br /&gt;       this.employeeService = employeeService;&lt;br /&gt;   }&lt;br /&gt;   protected String[] getConfigLocations() {&lt;br /&gt;       return new String[] {"classpath:/com/ibm/dw/spring2/dwspring2-service.xml"};&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;After that, in order to run the test,  one needs to include all the dependency JARs from Spring and Hibernate libraries, which includes the MySQL driver file. A &lt;span style="font-style: italic;"&gt;persistence.xml&lt;/span&gt; file is required by the JPA specification. It describes a &lt;span style="font-style: italic;"&gt;persistence unit&lt;/span&gt;, though in this case, it is only there to satisfy specs. The file is placed in the META-INF folder and must be accessible through the classpath. The code is below:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;persistence-unit name="dwSpring2Jpa" type="RESOURCE_LOCAL"&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now the web application comes into play. The UI for this is Spring MVC, and the first controller class created is &lt;span style="font-style: italic;"&gt;MainController&lt;/span&gt;, which handles the initial incoming request. It obtains a list of all the employees in the system. Next the &lt;span style="font-style: italic;"&gt;dwspring2-servlet.xml&lt;/span&gt; (&lt;span style="font-style: italic;"&gt;dwspring2 &lt;/span&gt;being the name of the DispatcherServlet) file is configured with all the beans required by Spring MVC. The &lt;span style="font-style: italic;"&gt;web.xml&lt;/span&gt; file contains the configuration of the &lt;span style="font-style: italic;"&gt;DispatcherServlet &lt;/span&gt;and is located in the WEB-INF folder. &lt;span style="font-style: italic;"&gt;MainController&lt;span style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;does not display the data it holds, instead it hands the data over to a  view which resolves to a jsp file, &lt;span style="font-style: italic;"&gt;home.jsp&lt;/span&gt; located in the jsp folder. &lt;span style="font-style: italic;"&gt;home.jsp&lt;/span&gt; displays the id and full name of each employee, it also made links out of the ids. When clicked, the links go to the controller &lt;span style="font-style: italic;"&gt;EmpDetailsController &lt;/span&gt;which gets all details about a particular employee (in other words, get the employee object). A command class, &lt;span style="font-style: italic;"&gt;EmployeeDetailsCommand&lt;/span&gt;, is used to parse the link arguments into an object. Here, the only arguments being passed is the employee id, so &lt;span style="font-style: italic;"&gt;EmployeeDetailsCommand &lt;/span&gt;has only one data field and a getter and setter.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;EmpDetailsController &lt;/span&gt;passes the employee object it holds to the &lt;span style="font-style: italic;"&gt;empdetails &lt;/span&gt;view which as before is resolved by the &lt;span style="font-style: italic;"&gt;InternalResourceViewResolver &lt;/span&gt;by appending the appropriate prefix and suffix and returns &lt;span style="font-style: italic;"&gt;/jsp/empdetails.jsp&lt;/span&gt; as the view handler. &lt;span style="font-style: italic;"&gt;empdetails.jsp&lt;/span&gt; displays the employee's details.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;home.jsp&lt;/span&gt;&lt;span&gt; and &lt;/span&gt;&lt;span style="font-style: italic;"&gt;empdetails.jsp&lt;/span&gt;&lt;span&gt; use the &lt;span style="font-style: italic;"&gt;css/dwstyles.css&lt;/span&gt; stylesheet to format their HTML. This only affect appearance.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;The next step is the Eclipse WTP process, however it has been replaced with an Ant build. This step will compile the code, build a deployable WAR file (for deployment in a J2EE compatible Web tier container) and deploy that file to a Tomcat server. The WAR file consists of the compiled classes, the dependency library jars, the web content and the configuration files (&lt;span style="font-style: italic;"&gt;context.xml&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;persistence.xml&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;dwspring2-servlet.xml&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="font-style: italic;"&gt; &lt;/span&gt; &lt;span style="font-style: italic;"&gt;dwspring-service.xml, &lt;/span&gt;&lt;span style="font-style: italic;"&gt;web.xml&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Before the WAR file can be deployed, a number of things had to be done. When a Spring JPA application runs on Tomcat, bytecode "weaving" during class loading is required for the JPA support to work properly. The standard Tomcat classloader does not support this.  A Spring-specific classloader is needed.&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Installing the Spring classloader:&lt;br /&gt;1) Copy &lt;span style="font-style: italic;"&gt;spring-tomcat-weaver.jar&lt;/span&gt; into the Tomcat's server/lib subdirectory. The &lt;span style="font-style: italic;"&gt;spring-tomcat-weaver.jar&lt;/span&gt; library can be found in the dist/weaver of the Spring distribution.&lt;br /&gt;2) Configure the &lt;span style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;context.xml&lt;/span&gt; file (located in META-INF) to let Tomcat know to replace the standard classloader for this particular web application.&lt;br /&gt;&lt;br /&gt;Spring needed to hook into Tomcat's context loading pipeline so a &lt;span style="font-style: italic;"&gt;ContextLoaderListener &lt;/span&gt;was added to &lt;span style="font-style: italic;"&gt;web.xml&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Datasources are managed by Tomcat and are available through a standard Java Naming and Directory Interface (JNDI) lookup mechanism. The employee system runs as a Web application inside Tomcat and should obtain its datasource through Tomcat's JNDI. To accomplish this, the MySQL driver needs to be copied to Tomcat's common/lib subdirectory. Then configure the &lt;span style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;context.xml&lt;/span&gt; file, adding a JNDI resource. With a resource name of "&lt;span style="font-style: italic;"&gt;jdbc/dwspring2&lt;/span&gt;", the configuration makes the JNDI datasource available through the name &lt;span style="font-style: italic;"&gt;java:comp/env/jdbc/dwspring2&lt;/span&gt;. Next, add a resource reference in &lt;span style="font-style: italic;"&gt;web.xml&lt;/span&gt;, making it available for use within the web application. Finally, &lt;span style="font-style: italic;"&gt;dwspring2-service.xml&lt;/span&gt; must be modified to use the JNDI datasource.&lt;br /&gt;&lt;br /&gt;The Spring engine needs to locate and process the bean configuration file (&lt;span style="font-style: italic;"&gt;dwspring2-service.xml&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; for the POJOs in order to wire them up with the web application. The context parameter in &lt;span style="font-style: italic;"&gt;web.xml &lt;/span&gt;must be configured with the location of the file.&lt;br /&gt;&lt;br /&gt;The final step before deployment is to fill the database with data. The &lt;span style="font-style: italic;"&gt;FillTableWithEmployeeInfo &lt;/span&gt;class was coded to do this. This class extends &lt;span style="font-style: italic;"&gt;AbstractJpaTests&lt;/span&gt;. A great feature of tests based on &lt;span style="font-style: italic;"&gt;AbstractJpaTests &lt;/span&gt;is that all database changes are rolled back upon completion of a test, allowing the next test to run quickly. However calling the &lt;span style="font-style: italic;"&gt;setComplete&lt;/span&gt;() method within the test commits the transaction instead of rolling it back and makes the changes permanent. Which is what is done with &lt;span style="font-style: italic;"&gt;FillTableWithEmployeeInfo&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Finally the WAR file (&lt;span style="font-style: italic;"&gt;spring2web.war&lt;/span&gt;) can be deployed to Tomcat's webapps subdirectory and loaded. However the deployment was unsuccessful.&lt;br /&gt;&lt;br /&gt;From Tomcat's Catalina log, it was a puzzling one-liner error about the context listener. Set up the web application logging by adding &lt;span style="font-style: italic;"&gt;log4j.properties&lt;/span&gt; in order to find out what was wrong. The error was more verbose, essentially a &lt;span style="font-style: italic;"&gt;ClassDefNotFoundException &lt;/span&gt;of a class in &lt;span style="font-style: italic;"&gt;jasper-compiler.jar&lt;/span&gt;, which is located in Tomcat's common/lib subdirectory. Adding that file to the web application library only made it a &lt;span style="font-style: italic;"&gt;ClassCastException&lt;/span&gt;. The project was stuck for a while.&lt;br /&gt;&lt;br /&gt;Got hold of the &lt;span style="font-style: italic;"&gt;springjpa&lt;/span&gt; project from &lt;a href="http://www.memestorm.com/blog/java-persistence-api-jpa-spring-and-eclipse-web-tools-platform-wtp/"&gt;MemeStorm&lt;/a&gt;, and tried to deploy that as well. Whilst doing that, changed the &lt;span style="font-style: italic;"&gt;loadTimeWeaver &lt;/span&gt;property in &lt;span style="font-style: italic;"&gt;dwspring2-service.xml&lt;/span&gt;&lt;span&gt; from &lt;/span&gt;&lt;span style="font-style: italic;"&gt;SimpleLoadTimeWeaver&lt;/span&gt; to &lt;span style="font-style: italic;"&gt;InstrumentationLoadTimeWeaver&lt;/span&gt; &lt;span&gt;to follow the &lt;span style="font-style: italic;"&gt;springjpa &lt;/span&gt;project. Read that &lt;/span&gt;&lt;span style="font-style: italic;"&gt;SimpleLoadTimeWeaver&lt;/span&gt; was only suited for testing, so for real deployment, &lt;span style="font-style: italic;"&gt;InstrumentationLoadTimeWeaver&lt;/span&gt;  or &lt;span style="font-style: italic;font-size:100%;" &gt;ReflectiveLoadTimeWeaver &lt;/span&gt;should be used. Whatever the problem was, it wasn't the  &lt;span style="font-style: italic;"&gt;loadTimeWeaver &lt;/span&gt;property as both applications still refused to deploy.&lt;br /&gt;&lt;br /&gt;Eventually learned that it was the Spring class loader at fault. When Tomcat replaced the standard classloader with the Spring classloader, the Spring classloader does not have the classpath the standard classloader possess in order to access Tomcat's library jars. The solution was to add the attribute &lt;span style="font-style: italic; font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;useSystemClassLoaderAsParent="false"&lt;/span&gt; to the Loader in &lt;span style="font-style: italic;"&gt;context.xml&lt;/span&gt;. The error was hurdled but a new one popped up.&lt;br /&gt;&lt;br /&gt;The new error was that no persistence units were parsed from META-INF/persistence.xml. This one was simple to solve, the META-INF/persistence.xml needed to be in the root of the class package. So a move to the web application's WEB-INF/classes and it is solved.&lt;br /&gt;&lt;br /&gt;The next error was talking about a java agent and prior reading indicates this had to do with the &lt;span style="font-style: italic;"&gt;InstrumentationLoadTimeWeaver&lt;/span&gt;, basically it needs a Spring agent to be loaded into the JVM. To accomplish this in Tomcat, the line &lt;span style="font-style: italic; font-weight: bold;"&gt;set JAVA_OPTS=%JAVA_OPTS% -javaagent:"%CATALINA_BASE%\server\lib\spring-agent.jar"&lt;/span&gt; was inserted  into &lt;span style="font-style: italic;"&gt;catalina.bat&lt;/span&gt; in Tomcat's bin subdirectory. The &lt;span style="font-style: italic;"&gt;spring-agent.jar&lt;/span&gt;&lt;span&gt; mentioned in the line can be found in &lt;/span&gt;the dist/weaver of the Spring distribution. The file was copied to Tomcat's server/lib subdirectory.&lt;br /&gt;&lt;br /&gt;Success! Deployment went without a hitch and the web application can be accessed, displaying the list of employees previously inserted into the database and their details when their link was clicked.&lt;br /&gt;&lt;br /&gt;Messed around with the &lt;span style="font-style: italic;"&gt;loadTimeWeaver &lt;/span&gt;property, changing it back to &lt;span style="font-style: italic;"&gt;SimpleLoadTimeWeaver&lt;/span&gt; and even commenting it out as Hibernate apparently does not require it. The web application still runs fine.&lt;br /&gt;&lt;br /&gt;One last change was the addition of &lt;span style="font-style: italic;"&gt;index.jsp&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;include.jsp&lt;/span&gt;, which were from a previous project. A slight modification to the welcome file in &lt;span style="font-style: italic;"&gt;web.xml&lt;/span&gt; and one can now access the web application via &lt;span style="font-weight: bold;"&gt;http://localhost:8080/spring2web&lt;/span&gt; without any need for a filename.&lt;br /&gt;&lt;br /&gt;The file structure of the spring2web web application:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;spring2web&lt;br /&gt;|-css&lt;br /&gt;|  |-dwstyles.css&lt;br /&gt;|&lt;br /&gt;|-jsp&lt;br /&gt;| |-empdetails.jsp&lt;br /&gt;| |-home.jsp&lt;br /&gt;| |-include.jsp&lt;br /&gt;|&lt;br /&gt;|-META-INF&lt;br /&gt;| |-context.xml&lt;br /&gt;|&lt;br /&gt;|-WEB-INF&lt;br /&gt;| |-classes&lt;br /&gt;| | |-com.ibm.dw.spring2.*&lt;br /&gt;| | |-com.ibm.dw.spring2.web.*&lt;br /&gt;| | |&lt;br /&gt;| | |-META-INF&lt;br /&gt;| | | |-persistence.xml&lt;br /&gt;| | |&lt;br /&gt;| | |-log4j.properties&lt;br /&gt;| |&lt;br /&gt;| |-lib&lt;br /&gt;| | |-*.jar&lt;br /&gt;| |&lt;br /&gt;| |-dwspring2-service.xml&lt;br /&gt;| |-dwspring2-servlet.xml&lt;br /&gt;| |-web.xml&lt;br /&gt;|&lt;br /&gt;|-index.jsp&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;The steps taken in Spring-JPA-Tomcat:&lt;br /&gt;- POJOs&lt;br /&gt;- Unit Test&lt;br /&gt;- dwspring2-service.xml&lt;br /&gt;- Integration Test&lt;br /&gt;- META-INF/persistence.xml&lt;br /&gt;- Spring MVC&lt;br /&gt;- dwspring2-servlet.xml&lt;br /&gt;- web.xml&lt;br /&gt;- META-INF/context.xml (not at the same location as persistence.xml)&lt;br /&gt;- (Tomcat)/common/lib &lt;-- mysql-connector-java-5.0.4-bin.jar&lt;br /&gt;- (Tomcat) /server/lib &lt;-- spring-tomcat-weaver.jar, spring-agent.jar&lt;br /&gt;- (Tomcat)/bin/catalina.bat &lt;-- Java agent command  &lt;h2 style="font-family: georgia; font-weight: normal;"&gt;&lt;/h2&gt;&lt;a href="http://www.memestorm.com/blog/java-persistence-api-jpa-spring-and-eclipse-web-tools-platform-wtp/"&gt; &lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-2676802930256726925?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/2676802930256726925/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=2676802930256726925' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2676802930256726925'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2676802930256726925'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/02/spring-jpa-tomcat.html' title='Spring-JPA-Tomcat'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-3698355386850947579</id><published>2007-02-12T10:33:00.000+08:00</published><updated>2007-01-29T19:50:28.529+08:00</updated><title type='text'>JSP Front End Testing</title><content type='html'>With the JSP front end, all correct operations dealing with valid employee ids will work.&lt;br /&gt;&lt;br /&gt;As there is no error correction and no validation, there are a lot of bad cases:&lt;br /&gt;Insert: Anything can be inserted. An employee id with null for every field is possible.&lt;br /&gt;&lt;br /&gt;Update: With a valid id, all the fields can be updated with junk data, even nulled. Without a valid id, the server creates an exception.&lt;br /&gt;&lt;br /&gt;Delete: Valid ids will be deleted, invalid ones will create an exception report.&lt;br /&gt;&lt;br /&gt;Find: Valid ids will be displayed, invalid ones will display a blank page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-3698355386850947579?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/3698355386850947579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=3698355386850947579' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3698355386850947579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3698355386850947579'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/02/jsp-front-end-testing.html' title='JSP Front End Testing'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4296426258469611207</id><published>2007-01-29T13:12:00.000+08:00</published><updated>2007-04-26T10:52:59.600+08:00</updated><title type='text'>Spring in Action</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="font-family: georgia;font-family:georgia;" id="comment_text_0" &gt;&lt;span&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Inversion of Control&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt; &lt;span style=";font-family:lucida grande;font-size:100%;"  &gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;Inversion of Control&lt;/span&gt;&lt;span style="font-family:lucida grande;"&gt; (IoC) is the reversal of responsibility with regard to how an object obtains references to other objects. Normally, each object is responsible for obtaining its own references to its dependencies. With IoC, objects are given their dependencies at creation time by an external entity which handles all the objects in the system.&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;pre id="comment_text_0" face="georgia"&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-weight: bold;font-family:georgia;font-size:130%;"  &gt;Dependency Injection&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family:lucida grande;"&gt;Dependency Injection is merely a more apt name for IoC, given that dependencies are injected into objects. There are 3 types of IoC:&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;1) Interface Dependent - Dependencies are managed by implementing special interfaces.&lt;br /&gt;2) Setter Injection - Dependencies and properties are configured via the setter methods.&lt;br /&gt;3) Constructor Injection - Dependencies and properties are configured via the constructor.&lt;br /&gt;&lt;br /&gt;IoC allow the Java objects to be loosely coupled, interacting through interfaces. It allows the programmer to set up and configure the objects as desired, while leaving little trace of it in the code itself.&lt;br /&gt;&lt;br /&gt;Application design for Spring would be based on interfaces. Overall, the code would be normal POJO, until arriving at the Spring setup; a class using all the objects coded and a Spring configuration file, usually XML.&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family:georgia;"&gt; &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4296426258469611207?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4296426258469611207/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4296426258469611207' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4296426258469611207'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4296426258469611207'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/spring-in-action.html' title='Spring in Action'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7689305833713641033</id><published>2007-01-18T18:06:00.000+08:00</published><updated>2007-01-18T19:11:56.585+08:00</updated><title type='text'>Native Hibernate vs. Hibernate JPA</title><content type='html'>Native Hibernate uses only the Hibernate Core for all its functions. The code for a class that will be saved to the database is displayed below:&lt;br /&gt;&lt;blockquote&gt;package hello;&lt;br /&gt;public class Message {&lt;br /&gt;    private Long id;&lt;br /&gt;    private String text;&lt;br /&gt;    private Message nextMessage;&lt;br /&gt;    // Constructors, getters, setters...&lt;br /&gt;}&lt;/blockquote&gt;As can be seen, it is merely a Plain Old Java Object (POJO). The relational mapping that links the object to the database table is in an XML mapping document. The actual code that will create and save the object is below:&lt;br /&gt;&lt;blockquote&gt;package hello;&lt;br /&gt;import java.util.*;&lt;br /&gt;import org.hibernate.*;&lt;br /&gt;import persistence.*;&lt;br /&gt;public class HelloWorld {&lt;br /&gt;    public static void main(String[] args) {&lt;br /&gt;        // First unit of work&lt;br /&gt;        Session session = HibernateUtil.getSessionFactory().openSession();&lt;br /&gt;        Transaction tx = session.beginTransaction();&lt;br /&gt;        Message message = new Message("Hello World");&lt;br /&gt;        Long msgId = (Long) session.save(message);&lt;br /&gt;        tx.commit();&lt;br /&gt;        session.close();&lt;br /&gt;        // Shutting down the application&lt;br /&gt;        HibernateUtil.shutdown();&lt;br /&gt;    }&lt;br /&gt;}&lt;/blockquote&gt;Session, Transaction and Query (not shown) objects are available due to the org.hibernate import. They allow a higher-level handling of database tasks than DAO using JDBC.&lt;br /&gt;&lt;br /&gt;Hibernate JPA is accessed through the use of Hibernate EntityManager and Hibernate Annotations. The Hibernate EntityManager is merely a wrapper around Hibernate Core, providing and supporting JPA functionality. Thus the change in the code can be seen below:&lt;br /&gt;&lt;blockquote&gt;package hello;&lt;br /&gt;import javax.persistence.*;&lt;br /&gt;@Entity&lt;br /&gt;@Table(name = "MESSAGES")&lt;br /&gt;public class Message {&lt;br /&gt;@Id @GeneratedValue&lt;br /&gt;@Column(name = "MESSAGE_ID")&lt;br /&gt;private Long id;&lt;br /&gt;@Column(name = "MESSAGE_TEXT")&lt;br /&gt;private String text;&lt;br /&gt;@ManyToOne(cascade = CascadeType.ALL)&lt;br /&gt;@JoinColumn(name = "NEXT_MESSAGE_ID")&lt;br /&gt;private Message nextMessage;&lt;/blockquote&gt;The XML document with all the relational data has been removed and replaced with inline annotations, which is provided by the javax.persistence import. The only difference between the Hibernate POJO and JPA POJO is the annotations. The code itself will run fine, the annotations make it a persistent entity but will do nothing unless Hibernate goes through it. JPA can glean enough information from them for the ORM and persistence tasks. The HelloWorld code:&lt;br /&gt;&lt;blockquote&gt;package hello;&lt;br /&gt;import java.util.*;&lt;br /&gt;import javax.persistence.*;&lt;br /&gt;public class HelloWorld {&lt;br /&gt;public static void main(String[] args) {&lt;br /&gt;// Start EntityManagerFactory&lt;br /&gt;EntityManagerFactory emf =&lt;br /&gt;Persistence.createEntityManagerFactory("helloworld");&lt;br /&gt;// First unit of work&lt;br /&gt;EntityManager em = emf.createEntityManager();&lt;br /&gt;EntityTransaction tx = em.getTransaction();&lt;br /&gt;tx.begin();&lt;br /&gt;Message message = new Message("Hello World");&lt;br /&gt;em.persist(message);&lt;br /&gt;tx.commit();&lt;br /&gt;em.close();&lt;br /&gt;// Shutting down the application&lt;br /&gt;emf.close();&lt;br /&gt;}&lt;br /&gt;}&lt;/blockquote&gt;The Hibernate import is gone, replace by javax.persistence. The EntityManagerFactory, EntityManager and EntityTransaction run the database tasks.&lt;br /&gt;&lt;br /&gt;Both API seem similar and choosing one over the other is a matter of preference. Native Hibernate is the cleaner one, with the relational data put into an XML document. Hibernate JPA is standardised with Java and can be ported easily.&lt;br /&gt;&lt;br /&gt;Other JPA implementations:&lt;br /&gt;Open-source:&lt;br /&gt;GlassFish&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Apache OpenJPA&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Commercial:&lt;br /&gt;SAP NetWeaver&lt;br /&gt;Oracle TopLink&lt;br /&gt;BEA Kodo&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7689305833713641033?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7689305833713641033/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7689305833713641033' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7689305833713641033'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7689305833713641033'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/native-hibernate-vs-hibernate-jpa.html' title='Native Hibernate vs. Hibernate JPA'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-1327951385335715098</id><published>2007-01-18T10:15:00.000+08:00</published><updated>2007-01-18T11:12:06.768+08:00</updated><title type='text'>HIbernate</title><content type='html'>Hibernate is an open-source project that handles the role of the persistence layer, becoming the middleman between the business logic code and the database data.  Its expressed purpose is to free developers from the tedious and common  coding of database tasks such as queries, insertions and deletions.&lt;br /&gt;&lt;br /&gt;Take the previous DAOExercise as an example, where most of the code dealt with inserting, selecting and deleting data from the MySQL database. Hibernate would handle these mundane tasks and allow the developer to focus more on the business logic and rare SQL code exceptions.&lt;br /&gt;&lt;br /&gt;HIbernate incorporates ORM (object/relational mapping), which will map objects to their proper tables in the database. Such logic would be used when hand-coding DAOs using raw JDBC, and it would be up to the developer to track and maintain any changes in either object or database table. Use of Hibernate simplifies matters and make maintenance easier.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-1327951385335715098?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/1327951385335715098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=1327951385335715098' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1327951385335715098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1327951385335715098'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/hibernate.html' title='HIbernate'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-735018810078425689</id><published>2007-01-17T11:48:00.000+08:00</published><updated>2007-01-17T12:09:51.103+08:00</updated><title type='text'>Object Pool Pattern</title><content type='html'>The Object Pool pattern dictates having an object (usually a singleton) maintain a pool of reusable objects that can be checked out and in by clients who will use them. Connections to databases are the perfect candidate for this pattern.&lt;br /&gt;&lt;br /&gt;The ConnectionFactory (CF) in the DAOExercise can be the connection-pool manager with the clients being the DAO classes. A DAO class request a connection from the CF for a query. The CF checks its pool; if there is no objects in the pool, it creates one and sends it to the DAO class, else it will pop out the object and return it. Once the DAO class is done with the query, it sends the connection back to CF and the CF puts it into the pool. The pool may have a maximum number of objects, whereby if all objects have been checked out and the CF tries to create one, it cannot and must wait for the return of an object to honour the request by the DAO class.&lt;br /&gt;&lt;br /&gt;The Object Pool pattern benefit designs with a resource creation that is expensive, limited in number  or slow that must be shared out to clients utilizing that resource. Real-world examples of the design are car rentals and timesharing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-735018810078425689?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/735018810078425689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=735018810078425689' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/735018810078425689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/735018810078425689'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/object-pool-pattern.html' title='Object Pool Pattern'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-5035344108898763454</id><published>2007-01-17T09:02:00.000+08:00</published><updated>2007-01-17T09:57:42.361+08:00</updated><title type='text'>Factory Method Pattern vs. Abstract Factory Pattern</title><content type='html'>The Factory Method pattern is to define an interface for creating an object but let subclasses decide the class to instantiate. For example the UIBuilder class contains two method stubs. The subclasses (EnglishUIBuilder, MalayUIBuilder) have to implement these stubs in their own way.&lt;br /&gt;&lt;br /&gt;The Abstract Factory pattern is to provide an interface for creating families of related or dependent objects without specifying their concrete classes. This pattern is often used in conjunction with the Factory Method pattern, thus it can be seen as a factory of factory objects.&lt;br /&gt;&lt;br /&gt;The UIFactory static method returns a subclass of UIFactory which in turn creates the appropriate UIBuilder object. The UIFactory subclass returned is determined by reading a config file and using the default value.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-5035344108898763454?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/5035344108898763454/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=5035344108898763454' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5035344108898763454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5035344108898763454'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/factory-method-pattern-vs-abstract.html' title='Factory Method Pattern vs. Abstract Factory Pattern'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4378585550939621681</id><published>2007-01-16T08:36:00.000+08:00</published><updated>2007-01-16T14:16:59.998+08:00</updated><title type='text'>MySQL Class</title><content type='html'>Prior to the addition of the ConnectionFactory, connection to the database was handled by the MySQL class. The class was to return a connection to any caller via a getter method.&lt;br /&gt;&lt;br /&gt;The connection was made static in the class,  letting only one instance to be created. All the methods were static, thus the class need not be instantiated. With that, a static initializer was added to run once the class was loaded, establishing the connection.&lt;br /&gt;&lt;br /&gt;For testing purposes, one connection is enough. In a live environment, the one connection that MySQL has would be swamped with requests. A pool of connections would be best for that sort. So at the time, the choice for a single connection was appropriate however it would not be scaleable outside test conditions.&lt;br /&gt;&lt;br /&gt;The static initializer was to initialize and establish the connection. This was done when the class is loaded, in other words when a static method is called. That will be the getter method being called. Initialization can take place inside the getter or another method, however since theus connection is static and only needs to be established once, the static initializer is used.&lt;br /&gt;&lt;br /&gt;When one has an open connection, one should provide a way of closing it. That was the closeConnection method. Ideally, once the connection has been used by a class, the class should close it. Going through DAOExercise; discovered that once closed, a connection cannot be reopened. Thereafter the only use for it was when all the tests were done in the AllTests class.&lt;br /&gt;&lt;br /&gt;In retrospect, using the static initializer was not a good idea. It would be better to stick it in the getter method:&lt;br /&gt;&lt;br /&gt;public static Connection getConnection()&lt;br /&gt;{&lt;br /&gt;if(conn.isClosed() || conn == null)&lt;br /&gt;{establishConnection();}&lt;br /&gt;return conn ;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;This way, closeConnection can be used.&lt;br /&gt;&lt;br /&gt;Addendum: Static reference creates only one instance for the class; all class objects share that static reference. As MySQL is never instantiated, that point is moot. Not so for the DAOExercise objects, two EmployeeDAOImpl objects will share the static connection.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4378585550939621681?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4378585550939621681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4378585550939621681' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4378585550939621681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4378585550939621681'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/mysql-class.html' title='MySQL Class'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7369468428630839988</id><published>2007-01-15T13:46:00.000+08:00</published><updated>2007-01-15T17:13:40.958+08:00</updated><title type='text'>Abstract Factory Pattern for DAOExercise</title><content type='html'>The Abstract Factory Pattern allows for multiple factories which share a common theme to be streamlined into one class. In DAOExercise, this class is the ConnectionFactory which will create the appropriate factory for use. This class currently has a concrete implementation for MySQLConnectionFactory and can be further extended (OracleConnectionFactory, OCBCConnectionFactory, etc).&lt;br /&gt;&lt;br /&gt;This implementation allows the underlying database (MySQL) to be divorced from the actual DAOExercise (Employee, Address, Dependent) so any database change (e.g Switch from MySQL to Oracle) can be coded and inserted into the ConnectionFactory, touching very little of the code for DAOExercise.&lt;br /&gt;&lt;br /&gt;Another way of looking at ConnectionFactory is that it is a factory of factories. The ConnectionFactory determines which factory is to be handed over to the client code via a string which must be set by the client code. The MySQLConnectionFactory will create and return a connection to the MySQL database. This outlook can be confusing when all the client code sees is the ConnectionFactory reference and not the actual factory object.&lt;br /&gt;&lt;br /&gt;Using this pattern for DAO creation (a DAOFactory generating EmployeeDAOFactory, AddressDAOFactory and DependentDAOFactory) is impossible with the current design as the implementing classes are not related to each other. The pattern can get around this with the use of the Adapter pattern but that would still require a major rewrite of the design. At best DAO creation is served by a single factory (DAOFactory) which will generate all three classes. Also unlike the ConnectionFactory, where the objects need different initializing data, the DAOFactory objects are self-contained.&lt;br /&gt;&lt;br /&gt;As the purpose of a factory is to generate objects for use, a single instance of it would suffice. Coding it so that it complies with the Singleton pattern would enforce this single instance. However, the pattern is not a requirement. Having multiple factories would not be a problem, save for efficiency and design.&lt;br /&gt;&lt;br /&gt;In MySQLConnectionFactory, there is a Properties variable which is used to read a file containing all database-specific information. Aside from the connection data, it stores all the SQL queries for that database. These queries are used in the DAO classes. It is not possible to create DAO objects with the file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7369468428630839988?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7369468428630839988/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7369468428630839988' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7369468428630839988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7369468428630839988'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/abstract-factory-pattern-for.html' title='Abstract Factory Pattern for DAOExercise'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4735815802754420462</id><published>2007-01-11T15:47:00.000+08:00</published><updated>2007-01-11T15:54:34.541+08:00</updated><title type='text'>DAOExercise Architecture</title><content type='html'>&lt;pre style="font-family: georgia;font-family:georgia;"  id="comment_text_0"&gt;&lt;span style="font-size:100%;"&gt;Having implemented and written DAO code that accesses a MySQL&lt;br /&gt;database, there need to be changes if that code is to access an&lt;br /&gt;Oracle database. Though both databases use SQL, code that works&lt;br /&gt;for one may be broken or have unexpected results in the other.&lt;br /&gt;So the SQL code needs to be tested and rewritten as necessary.&lt;br /&gt;The driver class needs to be rewritten with the proper commands&lt;br /&gt;and authentication so as to get the right connection to the Oracle&lt;br /&gt;database.&lt;br /&gt;&lt;br /&gt;Whenever the database changes, the Java code has to be&lt;br /&gt;rewritten to accommodate it. This is due to the hardcoding&lt;br /&gt;of the SQL and driver information. The only way to not rewrite&lt;br /&gt;all that is to throw it to a go-between which interacts with&lt;br /&gt;the database and leaves the Java code handling objects only.&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;span style="font-family: georgia;font-size:100%;" &gt; &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4735815802754420462?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4735815802754420462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4735815802754420462' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4735815802754420462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4735815802754420462'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/having-implemented-and-written-dao-code.html' title='DAOExercise Architecture'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4778891992211208208</id><published>2007-01-09T09:57:00.000+08:00</published><updated>2007-01-09T10:46:28.755+08:00</updated><title type='text'>SQL Injection</title><content type='html'>SQL Prepared Statements are apparently not subject to injection attacks. The precompiled code will view the wildcard parameters as data only. Attempts to subvert the code proved futile, with no change to the database. Proper arguments work and the code executes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4778891992211208208?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4778891992211208208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4778891992211208208' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4778891992211208208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4778891992211208208'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/sql-injection.html' title='SQL Injection'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-1864241880608131818</id><published>2007-01-08T15:29:00.000+08:00</published><updated>2007-01-08T15:58:08.860+08:00</updated><title type='text'>JDBC Basics</title><content type='html'>Learning how to use SQL via the Eclipse Java IDE and MySQL. Had problems connecting to the MySQL databases until I remembered to start up the service (&gt;_&lt;).&lt;br /&gt;&lt;br /&gt;The most crucial part was getting the connection through the DriverManager class and the settings for it. After that was the creation of tables and filling it with data. The tutorial at http://java.sun.com/docs/books/tutorial/jdbc/basics/tables.html was vague on that part and I had to go look elsewhere to do it.&lt;br /&gt;&lt;br /&gt;Used SELECT to print out the table values with the help of the ResultSet and Statement classes. Then looked into updating the data via Java methods instead of normal SQL commands.&lt;br /&gt;&lt;br /&gt;Prepared Statements are Statements given an SQL command at creation time. With wildcard parameters in the command, one can use it repeatedly, changing the parameters at will. Looked at the joining of two tables.&lt;br /&gt;&lt;br /&gt;The last was transactions, how to commit several statements as an atomic action. The Savepoint methods allowed part of the transaction to survive a rollback.&lt;br /&gt;&lt;br /&gt;One thing to keep in mind when building strings SQL commands is the spacing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-1864241880608131818?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/1864241880608131818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=1864241880608131818' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1864241880608131818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/1864241880608131818'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/jdbc-basics.html' title='JDBC Basics'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-2253768129946196323</id><published>2007-01-08T08:33:00.000+08:00</published><updated>2007-01-08T09:06:34.988+08:00</updated><title type='text'>SCJP Exam</title><content type='html'>4th January 2007, the day of the SCJP exam, scheduled for 10:00AM. Arrived at the testing centre, was told to leave all my things in a locker. That included the pens I brought, prompting the question - will I be provided pen and paper? Apparently I won't, they have marker pens and thin mousepad-sized writing-board sheets (1 pen, 2 sheets and a duster per tester). That was a let-down. Though it's understandable why they do so, I would be more comfortable with the old pen-and-paper standard. Using a marker pen to record one's answer is somewhat irritating.&lt;br /&gt;&lt;br /&gt;The questions were much simpler than expected, after the torture of going through the twisted self-test questions and mock exams. Even knowing that practice questions were harder than the real ones, I was still startled. 2 hours and 55 minutes is enough time to make an initial leisurely pass answering the 72 questions, bypassing over those with long convoluted code - sure to take some time to understand, a 2nd pass to wrap up unanswered questions and a quick 3rd pass to go through all the questions, minus the drag-and-drop ones. Spending time to record the answers for the drag-and-drop questions is  time that could have been better spent elsewhere. Reanswering those drag-and-drop questions is definitely a pain, since the answers are cleared when you want a second look at the questions.&lt;br /&gt;&lt;br /&gt;Overall, I think the preparation done for the SCJP exam was sufficient, as most of the questions I answered with confidence. Only with one question did I have really some doubt about what would happen (Oh, for a compiler at that time). So though I entered the exam with trepidation, I ended it with a very confident outlook. Of course, getting 13 questions wrong knocked me down with a good dose of humility, though a pass of 81% is not bad.&lt;br /&gt;&lt;br /&gt;Looking over the breakdown of the score, I did pretty good in Declarations, Initialization and Scoping, Collections/Generics, Fundamentals and got perfect marks for Flow Control. The areas where I was lacking were API Contents, Concurrency and OO Concepts. I was surprised about Concurrency, admittedly it is a complex topic but I did not struggle with any questions regarding it except for one which looked like a deadlock situation. API Contents and OO Concepts were no surprise to me, the mocks that did breakdown listed them as problem areas. However I elected to focus on Generics and Collections, feeling I had a shaky understanding of them, and it paid off.&lt;br /&gt;&lt;br /&gt;What I got from the entire affair? Aside from the SCJP certification, which I am not sure would be that useful, the one-month-plus training established a solid grounding in the standard Java language. It exposed me to the new features of Java 1.4 and 1.5. I'm not happy with Generics, thinking about it makes me feel like it is an abstract topic (in the literal, not Java, sense). I can use it for collections type-safety, though thinking about infesting wildcards, super and extends into classes and methods drives me off the deep end.&lt;br /&gt;&lt;br /&gt;=^.^= At last I can bind the SCJP book with chains, weight it down with rocks and dump it in the deepest, murkiest river I can find, all the while dancing and cackling madly. =^.^=&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-2253768129946196323?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/2253768129946196323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=2253768129946196323' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2253768129946196323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2253768129946196323'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2007/01/scjp-exam.html' title='SCJP Exam'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4103927964172374753</id><published>2006-12-22T13:31:00.000+08:00</published><updated>2006-12-22T15:02:51.526+08:00</updated><title type='text'>SCJP Chapter 10</title><content type='html'>&lt;span style="font-weight: bold;font-size:180%;" &gt;Development&lt;/span&gt;&lt;br /&gt;After the wringer that is threads,  this is a light read.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;javac and java&lt;/span&gt;&lt;br /&gt;The commands &lt;span style="font-family: courier new;"&gt;javac&lt;span style="font-family: georgia;"&gt; &lt;/span&gt;&lt;/span&gt;and &lt;span style="font-family: courier new;"&gt;java&lt;/span&gt; are used to compile and run java files. The command-line options that are available include &lt;span style="font-family: courier new;"&gt;-classpath&lt;/span&gt; (&lt;span style="font-family: courier new;"&gt;-cp&lt;/span&gt;), &lt;span style="font-family: courier new;"&gt;-d&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;-D&lt;/span&gt;. Multiple options and files must be separated by spaces.&lt;br /&gt;The &lt;span style="font-family: courier new;"&gt;-classpath&lt;/span&gt; or &lt;span style="font-family: courier new;"&gt;-cp&lt;/span&gt; option are paths that will be searched for classes. The  dot (&lt;span style="font-family: courier new;"&gt;.&lt;/span&gt;) indicates searching the current directory.  Any subdirectories listed will be searched but not the directories above them. With packages, classpaths become trickier. The root of the package must be in a subdirectory that is in the classpath, making it visible. It is important to understand the relative and absolute paths. With JAR files, one must include the name at the end of the path.&lt;br /&gt;The &lt;span style="font-family: courier new;"&gt;-d&lt;/span&gt; option tells the compiler where to put the class file that is generated. A compile error occurs if the destination directory does not exist. On the other hand, with a java file in a package, &lt;span style="font-family: courier new;"&gt;javac&lt;/span&gt; will build the package directories if none exist.&lt;br /&gt;The &lt;span style="font-family: courier new;"&gt;-D&lt;/span&gt; option creates a system property with the syntax of &lt;span style="font-style: italic;"&gt;name&lt;/span&gt;=&lt;span style="font-style: italic;"&gt;value&lt;/span&gt; following immediately with no spaces in-between, eg &lt;span style="font-family: courier new;"&gt;-Dkey=property&lt;/span&gt;. Should the value have spaces, it should be enclosed with quotes. Java provides a java.util.Properties class to obtain information on the system as well as adding more user properties. Two methods, setProperty() and getProperty() facilitate setting and getting a property. setProperty() takes two strings for the name-value pair and getProperty() returns a string while either taking one string for the name value or two strings, a name value and a default value if the property does not exist (similar to setProperty()).&lt;br /&gt;For &lt;span style="font-family: courier new;"&gt;java&lt;/span&gt;, exactly one class file is executed every time it is invoked, with no need for the extension. The argument declaration for the main method is no longer fixed to &lt;span style="font-family: courier new;"&gt;String[] args&lt;/span&gt;. The name of the string array can be changed and the var-args syntax may be used. &lt;span style="font-family: courier new;"&gt;String... x&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;String port[]&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;String[] ___&lt;/span&gt; are all legal.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Static Imports&lt;/span&gt;&lt;br /&gt;Static imports are a convenience-only feature that allows less typing. Beginning with the syntax:&lt;span style="font-family: courier new;"&gt; import static&lt;/span&gt;, which can only be used on static object references, constants (which are &lt;span style="font-family: courier new;"&gt;static&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;final&lt;/span&gt;) and &lt;span style="font-family: courier new;"&gt;static&lt;/span&gt; methods. Beware of ambiguously named &lt;span style="font-family: courier new;"&gt;static&lt;/span&gt; members, two classes may have a constant with the same name. If used, Java will not know which class to refer to.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4103927964172374753?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4103927964172374753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4103927964172374753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4103927964172374753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4103927964172374753'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/scjp-chapter-10.html' title='SCJP Chapter 10'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6503473128488962036</id><published>2006-12-20T15:02:00.000+08:00</published><updated>2006-12-21T18:53:54.976+08:00</updated><title type='text'>SCJP Chapter 9</title><content type='html'>&lt;span style="font-weight: bold;font-size:180%;" &gt;Threads&lt;/span&gt;&lt;br /&gt;There are two ways to define, create and run threads. One is to extend from the Thread class, overriding the default &lt;span style="font-family:courier new;"&gt;run()&lt;/span&gt; method with another implementation.  The other is to implement the Runnable interface, which only contains one method &lt;span style="font-family:courier new;"&gt;run()&lt;/span&gt;, and put in the &lt;span style="font-family:courier new;"&gt;run()&lt;/span&gt; code. With a Runnable implementor, a Thread instance needs to be created with the implementor in the argument, allowing the code to be threaded.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;States&lt;/span&gt;&lt;br /&gt;When a thread is created but not started using the &lt;span style="font-family:courier new;"&gt;start()&lt;/span&gt; method, it is in the &lt;span style="font-style: italic;"&gt;new&lt;/span&gt; state. Once started, it will graduate to the &lt;span style="font-style: italic;"&gt;runnable&lt;/span&gt; state and enters the runnable pool where threads wait for the scheduler to pick them and run them. The run order of runnable threads is not guaranteed. What is guaranteed is that each thread will start and each thread will run to completion. The &lt;span style="font-style: italic;"&gt;running &lt;/span&gt;state is what all threads aspire to. However, a thread may be pulled off by the &lt;span style="font-style: italic;"&gt;waiting&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;blocking&lt;/span&gt; or &lt;span style="font-style: italic;"&gt;sleeping&lt;/span&gt; states (If the scheduler does not pull it off first). In which case, the thread would still be alive but not eligible for running. Once a thread's &lt;span style="font-family:courier new;"&gt;run()&lt;/span&gt; method is done, the thread is &lt;span style="font-style: italic;"&gt;dead&lt;/span&gt;. And once the thread has been started, it can never be started again (Runtime exception).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Priorities&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Thread priorities are positive integers ranging from 1 to 10, though it is better to use the constants Thread.MIN_PRIORITY, Thread.NORM_PRIORITY and Thread.MAX_PRIORITY. The scheduler guarantees that the thread running will always have a greater or equal priority to the highest priority threads in the runnable pool.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Synchronization&lt;/span&gt;&lt;br /&gt;Race condition is a problem where multiple threads vie for access to a single object and in the process, corrupt the state of the object, producing data which is of no use to any of the threads.&lt;br /&gt;&lt;br /&gt;The solution to this is to lock methods or code blocks so that only one thread can access the object. Only code that can change the object needs be synchronized. Threads trying to get the object's lock, but discover it has already been taken, is said to be blocked on the object's lock. They go into a pool for that object and wait until the lock is released, whereby any of them can get it. Care has to be taken that deadlock does not occur. Deadlock is when two threads are blocked, with each waiting for the other's lock.&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Thread Interaction&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;wait()&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;notify()&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;notifyAll()&lt;/span&gt; are methods that deal with objects' locking status. These methods can be called on any objects, within a synchronized context. A thread cannot call these methods on an object unless it owns that object's lock. The thread that calls the &lt;span style="font-family: courier new;"&gt;wait()&lt;/span&gt; method on an object goes into a waiting room, i.e. sleeps, until the &lt;span style="font-family: courier new;"&gt;notify()&lt;/span&gt;/&lt;span style="font-family: courier new;"&gt;notifyAll()&lt;/span&gt; method is invoked on the same object. Thus &lt;span style="font-family: courier new;"&gt;wait()&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;notify()&lt;/span&gt; must be used on the same object.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6503473128488962036?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6503473128488962036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6503473128488962036' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6503473128488962036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6503473128488962036'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/scjp-chapter-9.html' title='SCJP Chapter 9'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-5803469709596666687</id><published>2006-12-19T15:09:00.000+08:00</published><updated>2006-12-19T17:00:30.777+08:00</updated><title type='text'>SCJP Chapter 8</title><content type='html'>&lt;span style="font-size:180%;"&gt;&lt;span style="font-weight: bold;"&gt;Inner Classes&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;There are four types of inner classes, your 'regular joe' inner class, method-local inner class, anonymous inner class and the static nested class (which is not really an inner class at all).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Regular Inner Class&lt;/span&gt;&lt;br /&gt;Beginning with the regular inner class, which is coded alongside the outer class's variable and method members, one needs to understand that the inner class has access to all of the outer class members. Even private ones. The outer class needs to create an instance of the inner class before it can begin accessing the inner class members. Also when calling from another class, the outer class need to be instantiated before one can instantiate the inner class:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;MyOuter.MyInner myinner = new MyOuter().new MyInner();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When in the inner class, the object self-reference is &lt;span style="font-family: courier new;"&gt;this&lt;/span&gt;&lt;span style="font-family: georgia;"&gt;. &lt;/span&gt;The outer class reference is &lt;span style="font-family: courier new;"&gt;NameofOuterClass.this&lt;span style="font-family: georgia;"&gt;. The same modifiers (&lt;span style="font-family: courier new;"&gt;final&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;abstract&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;public&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;private&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;protected&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;strictfp &lt;/span&gt;and &lt;span style="font-family: courier new;"&gt;static &lt;/span&gt;- though that changes it into a static nested class) that can be applied to instance variables and methods can also be applied to inner classes.&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Method-Local Inner Class&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; An inner class defined within a method, it requires instantiation (below the class definition) inside the method to be available for use. No other method or class can create the method-local inner class aside from the method which holds that class. Like regular inner classes, it can access the outer class members, however it cannot access the local variables inside the method containing it unless these variables are marked &lt;span style="font-family: courier new;"&gt;final&lt;/span&gt;. Local variables exist on the stack and within the method lifetime only. Only two modifiers for the method-local inner class, &lt;span style="font-family: courier new;"&gt;abstract &lt;/span&gt;or &lt;span style="font-family: courier new;"&gt;final&lt;span style="font-family: georgia;"&gt;.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Anonymous Inner Class&lt;/span&gt;&lt;br /&gt;Nameless inner classes with two versions, regular and argument-defined.&lt;br /&gt;&lt;br /&gt;The regular version has two flavors, creating a subclass of any class type and creating a class implementing an interface. Subclassing is used to override the methods of a superclass, however creating a new method is legal though there is no way to invoke it short of a compilation error. The syntax for both flavors is unusual:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-size:100%;" &gt;class Popcorn {&lt;br /&gt;    public void pop() {&lt;br /&gt;        System.out.println("popcorn");}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;interface Cookable{&lt;br /&gt;public void cook();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Food {&lt;br /&gt;    Popcorn p = new Popcorn(){&lt;br /&gt;        public void pop(){&lt;br /&gt;           System.out.println("anonymous popcorn");} };&lt;br /&gt;&lt;br /&gt;    Cookable c = new Cookable(){&lt;br /&gt;        public void cook(){&lt;br /&gt;            System.out.println("anonymous cookable implementor");} };&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Note the semicolon indicating the end of the statement. The semicolon is not present in argument-defined anonymous inner classes as the definition is located in the argument portion of the method call.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Static Nested Classes&lt;/span&gt;&lt;br /&gt;A class that is simply a static member of the enclosing class. Meaning it can be accessed without instantiating the enclosing class. Naturally being static, it can only access other static variables and methods. Syntax for it:&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt;MyOuter.StaticInner sinner = new MyOuter.StaticInner();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Or within the enclosing class, &lt;span style="font-family: courier new;"&gt;MyOuter&lt;/span&gt;:&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt;StaticInner sinner = new StaticInner();&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-5803469709596666687?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/5803469709596666687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=5803469709596666687' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5803469709596666687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5803469709596666687'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/scjp-chapter-8.html' title='SCJP Chapter 8'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-2550892830945954613</id><published>2006-12-18T16:47:00.000+08:00</published><updated>2006-12-18T18:25:46.909+08:00</updated><title type='text'>SCJP Chapter 7</title><content type='html'>The last of the big chapters, Chapter 7 deals with collections and generics.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Collections&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;    There are four interfaces (Lists, Sets, Maps and Queues) encompassing the eleven classes that implement them (ArrayList, Vector, LinkedList; HashSet, LinkedHashSet, TreeSet; Hashtable, LinkedHashMap, HashMap, TreeMap and PriorityQueue). Basically have to know what methods are available and how they are used, most of which is in the code done for the chapter.&lt;br /&gt;&lt;br /&gt;One thing to note is the equals() and hashCode() methods and their contracts. The methods come from the Object class and thus is present in every class afterwards.&lt;br /&gt;The default equals() consider two objects equal if the two references point to the same object, thus to get proper equality of objects (datawise), the equals() need to be overridden with the desired implementation. Otherwise, Sets will allow duplicates in and objects with the default cannot be used as keys in a hashtable. Read the contract (reflexive, symmetric, transitive, consistent and that for any non-null x x.equals(null) will return false) and watch out for questions on this and below.&lt;br /&gt;With equals() overridden, hashCode() must be overridden as well. The default will allow duplicates in a Set. The contract for this one is a bit trickier:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;For&lt;/span&gt;: x.equals(y) == true&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Required&lt;/span&gt;: x.hashCode() == y.hashCode()&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;For&lt;/span&gt;: x.hashCode() != y.hashCode()&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Required&lt;/span&gt;: x.equals(y) == false&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;For&lt;/span&gt;: x.hashCode() == y.hashCode()&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Allowed but not required&lt;/span&gt;: x.equals(y)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;For&lt;/span&gt;: x.equals(y) == false&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Allowed but not required&lt;/span&gt;: No hashCode requirements&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Generics&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:85%;"&gt;    Generics enforce compile-time type safety on Collections (and classes and methods declared with generic type parameters). A generic type (eg. Animal) can accept subtypes (eg. Dog, Cat, Wolf). One advantage to type safety is no cast is required when the element type is known. Passing type-safe code into non-type code is dangerous, the compiler will compile it under duress (giving out a warning).&lt;br /&gt;&lt;br /&gt;Polymorphism applies to base type, not generic type parameter:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;      Right&lt;/span&gt;:       List&lt;/span&gt;&lt;animal&gt;&lt;span style="font-size:85%;"&gt; aList = new ArrayList&lt;/span&gt;&lt;animal&gt;&lt;span style="font-size:85%;"&gt;();&lt;br /&gt;&lt;span style="font-style: italic;"&gt;      Wrong&lt;/span&gt;:    List&lt;/span&gt;&lt;animal&gt;&lt;span style="font-size:85%;"&gt; aList = new ArrayList&lt;/span&gt;&lt;dog&gt;&lt;span style="font-size:85%;"&gt;();&lt;br /&gt;The generic type must always be the same for declaration and initialization. Another problem is an ArrayList&lt;/span&gt;&lt;animal&gt;&lt;span style="font-size:85%;"&gt; will not accept any collections of an Animal subtype. This requires further reading.&lt;br /&gt;&lt;br /&gt;Wildcard ? allows any type to be assigned, but nothing can be added to the list referred to as List.&lt;br /&gt;With the extends keyword, List ? extends Animal will be able to assign any subtype of List and typed for &lt;/span&gt;&lt;animal&gt;&lt;span style="font-size:85%;"&gt; or anything that extends Animal (either subclasses or implementations), but still nothing can be added.&lt;br /&gt;With the super keyword, List  ? super Animal will be able to assign any subtype of List and typed for &lt;/span&gt;&lt;dog&gt;&lt;span style="font-size:85%;"&gt; or any supertype of Dog, and allows a restricted way of adding to the collection.&lt;br /&gt;&lt;br /&gt;One last thing to note is the use of generic typing in classes and methods, this allows type-checking to be built into the classes and methods, does away with the need to cast and the need to create several subclasses for different types.&lt;/span&gt;&lt;br /&gt;&lt;/dog&gt;&lt;/animal&gt;&lt;/animal&gt;&lt;/dog&gt;&lt;/animal&gt;&lt;/animal&gt;&lt;/animal&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-2550892830945954613?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/2550892830945954613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=2550892830945954613' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2550892830945954613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2550892830945954613'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/scjp-chapter-7.html' title='SCJP Chapter 7'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-6424395189211453029</id><published>2006-12-13T13:15:00.000+08:00</published><updated>2006-12-13T14:06:47.005+08:00</updated><title type='text'>SCJP Chapter 6</title><content type='html'>Of strings, I/O, formatting and parsing.&lt;br /&gt;&lt;br /&gt;Starting with Strings, which are immutable, there are also mutable StringBuffers and StringBuilders (added as of Java 5). The latter two are the same except that StringBuilders are faster because they are not synchronized (and therefore thread-unsafe). Important stuff to remember; know the methods of all three classes, Strings have length() method and arrays have length variable, know the differences between Strings and the other two, and beware chained methods.&lt;br /&gt;&lt;br /&gt;For I/O, there are six classes to contend with; File, FileReader, BufferedReader, FileWriter, BufferedWriter and PrintWriter. Know about File's existential and creation problems.  Know about wrapping classes up to enable higher-level usage and which ones are legal. Be aware that PrintWriter, as of Java 5, can now be used by wrapping a File or String.&lt;br /&gt;&lt;br /&gt;Serialization is the saving of state of objects into a file for them to be read later (deserialization), reconstituting back the class objects. ObjectOutputStream and ObjectInputStream with their respective writeObject() and readObject() methods are the ones that allow the saving and loading of objects. Being higher-level classes, they need to be wrapped around the lower-level classes FileOutputStream and FileInputStream. A few things to note: all the classes to be serialized must either implement the Serializable interface or have a superclass that did. Any non-serializable object will cough up a runtime exception by the JVM. The &lt;span style="font-weight: bold;"&gt;transient &lt;/span&gt;keyword tells the serialization to skip a variable, not saving it. However, if there is need for that variable's state to be saved, one can override the writeObject() and readObject() to include it (the overriding code has to be in the class to be serialized). Constructors do not run for serialization, however a non-serializable superclass will run its constructor, potentially changing inherited variables. Lastly, serialization does not work for statics.&lt;br /&gt;&lt;br /&gt;To work with dates, numbers and currencies, these classes are available: Date, Calendar and Locale from java.util.*, DateFormat and NumberFormat from java.text.*. Calendar, DateFormat and NumberFormat use factory methods to initialize. Knowing how to use all the classes is essential.&lt;br /&gt;&lt;br /&gt;The last section of Chapter 6 deals with finding stuff (through regular expressions, of which there are two ways, pattern matching and searching using the Scanner class), tokenizing stuff (through String.split and using the Scanner class) and formatting stuff (Using printf and format, which are identical, C-style).&lt;br /&gt;&lt;br /&gt;Chapter 7, the return of the Generics!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-6424395189211453029?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/6424395189211453029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=6424395189211453029' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6424395189211453029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/6424395189211453029'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/scjp-chapter-6.html' title='SCJP Chapter 6'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7983347652771446442</id><published>2006-12-11T08:38:00.000+08:00</published><updated>2006-12-11T15:20:57.147+08:00</updated><title type='text'>SCJP Chapter 5</title><content type='html'>This chapter covers flow control; conditional &lt;span style="font-family: courier new;"&gt;if&lt;span style="font-family: georgia;"&gt; &lt;/span&gt;&lt;/span&gt;and &lt;span style="font-family: courier new;"&gt;switch&lt;/span&gt; statements, looping &lt;span style="font-family: courier new;"&gt;do-while&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;while&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;for&lt;/span&gt; statements, even exceptions and assertions.&lt;br /&gt;&lt;br /&gt;What's there to know about the &lt;span style="font-family: courier new;"&gt;if&lt;/span&gt; statement? It encompasses the &lt;span style="font-family: courier new;"&gt;if&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;if-else&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;if-elseif&lt;/span&gt; constructs. Things to beware of: unbraced statements (only one is in the if construct), lost &lt;span style="font-family: courier new;"&gt;else&lt;/span&gt; clause (belongs to the innermost if statement), misleading indentation and illegal expressions (must resolve to a boolean).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;switch&lt;/span&gt; statements can simulate multiple &lt;span style="font-family: courier new;"&gt;if&lt;/span&gt; statements. A &lt;span style="font-family: courier new;"&gt;switch&lt;/span&gt;'s expression takes an &lt;span style="font-family: courier new;"&gt;enum&lt;/span&gt; or variables that can be implicitly promoted to an &lt;span style="font-family: courier new;"&gt;int&lt;span style="font-family: georgia;"&gt; &lt;/span&gt;&lt;/span&gt;(&lt;span style="font-family: courier new;"&gt;char&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;byte&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;short&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;int&lt;/span&gt;) and it can use boxing. The value for a &lt;span style="font-family: courier new;"&gt;case&lt;/span&gt; must be a compile time constant. &lt;span style="font-family: georgia;"&gt;Cases &lt;/span&gt;with the same value will not compile. Neither will a &lt;span style="font-family: courier new;"&gt;case&lt;span style="font-family: georgia;"&gt; &lt;/span&gt;&lt;/span&gt;with a value larger than the type variable in the &lt;span style="font-family: courier new;"&gt;switch&lt;/span&gt;. Without &lt;span style="font-family: courier new;"&gt;break&lt;/span&gt; statements, the code will run top down starting from the execution &lt;span style="font-style: italic;"&gt;entry point&lt;/span&gt; (the first &lt;span style="font-family: courier new;"&gt;case&lt;/span&gt; constant matched). This dropping down is called "fall-through". &lt;span style="font-family: courier new;"&gt;default&lt;/span&gt; is executed when there is no match and its location does not matter; end, middle or top.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;do-while&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;while&lt;/span&gt; loops are the same except for these differences: &lt;span style="font-family: courier new;"&gt;do-while&lt;/span&gt; must run at least once (&lt;span style="font-family: courier new;"&gt;while&lt;/span&gt; may not run at all) and construction is different (note &lt;span style="font-family: courier new;"&gt;do-while&lt;/span&gt; ends in a semicolon).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;for&lt;/span&gt; loops has a second structure as of Java 5. The "enhanced &lt;span style="font-family: courier new;"&gt;for&lt;/span&gt; loop", a.k.a &lt;span style="font-family: courier new;"&gt;for-each&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;for-in&lt;/span&gt;, makes it easier to iterate through arrays and collections. The &lt;span style="font-family: courier new;"&gt;for-each&lt;/span&gt; loop has two components (declaration and expression) versus the three components of a &lt;span style="font-family: courier new;"&gt;for&lt;/span&gt; loop (initialization, condition and iteration).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;break&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;continue&lt;/span&gt; statements are used to halt a loop, either the entire loop (&lt;span style="font-family: courier new;"&gt;break&lt;/span&gt;) or the current iteration (&lt;span style="font-family: courier new;"&gt;continue&lt;/span&gt;). Labels are added when nested loops are involved, they enable the &lt;span style="font-family: courier new;"&gt;break&lt;/span&gt;/&lt;span style="font-family: courier new;"&gt;continue&lt;/span&gt; statement to apply to the labelled loop, not necessarily the loop the statement is in.&lt;br /&gt;&lt;br /&gt;Exceptions are handled by coding in &lt;span style="font-family: courier new;"&gt;try&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;catch&lt;/span&gt; blocks. A &lt;span style="font-family: courier new;"&gt;finally&lt;/span&gt; block can be added and will always run after the &lt;span style="font-family: courier new;"&gt;try&lt;/span&gt; block, regardless whether an exception is thrown or not. A &lt;span style="font-family: courier new;"&gt;try&lt;/span&gt; block cannot be used on its own, either a &lt;span style="font-family: courier new;"&gt;catch&lt;/span&gt; or a &lt;span style="font-family: courier new;"&gt;finally&lt;/span&gt; block must be present. An exception must find a match with a &lt;span style="font-family: courier new;"&gt;catch&lt;/span&gt; block or its supertype. A method must declare an exception if it throws (directly or indirectly) the exception otherwise it must handle the thrown exception. This is the "handle or declare" rule. Runtime exceptions are exempt from this rule. Need to know which exceptions are thrown by the Java Virtual Machine (JVM exceptions) and which are thrown explicitly by application programmers (Programmatic exceptions).&lt;br /&gt;&lt;br /&gt;Assertions test assumptions during development. Their default mode is off and must be specifically turned on. If an assertion is true, the code runs smoothly. If an assertion is false, an &lt;span style="font-family: courier new;"&gt;AssertionError&lt;/span&gt; is thrown, shutting down the application. Assertions have two versions, both versions have an expression that results in a boolean value, the difference is a second expression to be added to the stack for debugging purposes. Inappropriate uses of assertions are validating public method arguments, validating command-line arguments and assert expressions that cause side effects. Appropriate uses of assertions are validating private method arguments and, even in public methods, checking for cases that are not supposed to happen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7983347652771446442?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7983347652771446442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7983347652771446442' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7983347652771446442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7983347652771446442'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/scjp-chapter-5.html' title='SCJP Chapter 5'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-4774129378439069786</id><published>2006-12-07T13:15:00.000+08:00</published><updated>2006-12-07T14:53:17.713+08:00</updated><title type='text'>SCJP Chapter 4</title><content type='html'>A nice small focused chapter on operators. It starts with the assignment operator "=" and its compound kin (+=, -=, *=,/=). With the compound operators, the right side of the = will always be evaluated first, something to take note of.&lt;br /&gt;&lt;br /&gt;Relational operators (&lt;, &lt;=, &gt;, &gt;=, == and !=) are relatively straightforward. Comparison of characters use their Unicode value. Equality (==) for objects only check whether variables point to the same object, not whether two objects are the same.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:georgia;"&gt;The &lt;/span&gt;instanceof&lt;span style="font-family:georgia;"&gt; operator is used with object reference variables and checks for type. It returns true if the variable IS-A particular class (or superclass) or interface (indirectly or directly implemented). It is legal to test null eg. &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;null instanceof String&lt;span style="font-family:georgia;"&gt;, but it will always return false. It will&lt;span style="font-weight: bold;"&gt; not compile&lt;/span&gt; if testing a class with no relationship to the other class eg. &lt;span style="font-family:courier new;"&gt;Dog instanceof Cat&lt;/span&gt;&lt;span style="font-family:georgia;"&gt;. Last note: array IS-A Object.&lt;br /&gt;&lt;br /&gt;Arithmetic operators (+, -, *, /, %) are simple to understand. The remainder operator (%) divides two operands and returns the remainder as the result. The + operator can be used to concatenate strings and care must be taken to verify which role it is in. If either one of the operands are strings then it concatenates, otherwise it is a normal addition operator.&lt;br /&gt;&lt;br /&gt;Increment and decrement operators (++ and --) have two modes, prefix and postfix. Below shows a code example. These operators can not be used on final variables, doing so results in a compiler error.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;int x = 1;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;if(++x == 2)    // prefix, x is incremented to 2 and&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:courier new;"&gt;{ return true; }//&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:courier new;"&gt; the expression is evaluated,&lt;br /&gt;                // returning true&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;if(x++ == 2)    // postfix, the expression is&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:courier new;"&gt;{ return true; }//&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:courier new;"&gt; evaluated first, returning true&lt;br /&gt;                // then x is incremented to 3&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;The conditional operator is a ternary operator (with three operands). It is a miniature &lt;span style="font-family:courier new;"&gt;if&lt;/span&gt; statement. The structure is as below.&lt;br /&gt;&lt;br /&gt;x = (boolean expression) ?  value if &lt;span style="font-family:courier new;"&gt;true&lt;/span&gt; : value if &lt;span style="font-family:courier new;"&gt;false&lt;span style="font-family:georgia;"&gt;&lt;br /&gt;&lt;br /&gt;Logical operators (&amp;, |, ^, !, &amp;amp;&amp;, ||) are the last topic in the chapter. Short-circuit operators (&amp;amp;&amp; and ||) evaluate up to the operand they need to make a conclusive decision. AND (&amp;amp;&amp;) will return false upon the first operand resolving to false, and does not bother to check any other operands after that. Similarly, OR (||) will return true for the first operand resolving to true.&lt;br /&gt;The non-short-circuit operators (&amp;amp; and |) evaluate all the operands. This is a key point to remember. XOR (^) returns true when EXACTLY one operand is true. The ! operator returns the opposite of the boolean value.&lt;br /&gt;&lt;br /&gt;Onto chapter 5, where flow control rules.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-4774129378439069786?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/4774129378439069786/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=4774129378439069786' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4774129378439069786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/4774129378439069786'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/scjp-chapter-4.html' title='SCJP Chapter 4'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-2939297629476356664</id><published>2006-12-06T14:44:00.000+08:00</published><updated>2006-12-06T15:37:19.404+08:00</updated><title type='text'>SCJP Chapter 3</title><content type='html'>A lot of information in this one, a 'foundation' chapter indeed.&lt;br /&gt;&lt;br /&gt;Starting off with a look into assigning primitives and object references, which then necessitates casting types to the correct one.  Implicit casts are done when there is no loss of data, conversely explicit casts are needed when data is at risk of being truncated.&lt;br /&gt;&lt;br /&gt;A brief explanation on scope and lifetimes of variables followed by default initialization of instance and local variables. Watch out for shadow variables that exist in their own scope and override any other mimics.&lt;br /&gt;&lt;br /&gt;Arrays: declaration, construction and initialization. 1-D, 2-D or n-D; a lot of logic needed for this one.&lt;br /&gt;&lt;br /&gt;Wrapper classes for the primitives, enabling them to used as objects. Autoboxing is a new feature in Java 1.5, and is involved when overloading methods with wrappers. Overload paths - widening, autoboxing and var-args, in that order. Beware combination questions.&lt;br /&gt;&lt;br /&gt;Lastly is garbage collection. Once an object h&lt;span style="font-family: georgia;"&gt;as no references to it, it is ripe for collection. A request for garbage collection may be made but execution is &lt;/span&gt;&lt;span style="font-weight: bold; font-family: georgia;"&gt;not guaranteed&lt;/span&gt;&lt;span style="font-family: georgia;"&gt;. Similarly, the&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;finalize&lt;span style="font-family: georgia;font-family:arial;" &gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: georgia;font-family:arial;" &gt;m&lt;/span&gt;&lt;span style="font-family: georgia;"&gt;ethod is also not guaranteed. If &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;finalize&lt;span style="font-family:arial;"&gt;&lt;span style="font-family: georgia;"&gt; runs, it does so only once for an object and may save the object from deletion.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Onto chapter 4!&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-2939297629476356664?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/2939297629476356664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=2939297629476356664' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2939297629476356664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/2939297629476356664'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/scjp-chapter-3.html' title='SCJP Chapter 3'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8129673055857238855</id><published>2006-12-05T21:46:00.000+08:00</published><updated>2006-12-05T21:49:17.093+08:00</updated><title type='text'>Blackout</title><content type='html'>Power went out for the whole building around 3 o'clock. It seems that TNB (electric company) is to blame. Hopefully, by tomorrow it will be resolved.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8129673055857238855?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8129673055857238855/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8129673055857238855' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8129673055857238855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8129673055857238855'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/blackout.html' title='Blackout'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-3576725768340781366</id><published>2006-12-04T16:54:00.000+08:00</published><updated>2006-12-04T17:34:58.489+08:00</updated><title type='text'>SCJP Chapter 2</title><content type='html'>Overriding and overloading, potential mix-up. Overriding methods to replace the original code with something different. Overloading methods to increase the number of methods available.&lt;br /&gt;&lt;br /&gt;Constructors and their (default) construction. No-arg constructors, particularly default ones, are needed else beware of pitfalls in the super callers.&lt;br /&gt;&lt;br /&gt;A brief look on &lt;span style="font-style: italic;"&gt;static&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;static &lt;/span&gt;methods cannot access non-&lt;span style="font-style: italic;"&gt;static &lt;/span&gt;variables and methods.&lt;br /&gt;&lt;br /&gt;Misreading questions is hazardous to one's answers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-3576725768340781366?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/3576725768340781366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=3576725768340781366' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3576725768340781366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/3576725768340781366'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/scjp-chapter-2.html' title='SCJP Chapter 2'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-7650311021542318837</id><published>2006-12-04T11:43:00.000+08:00</published><updated>2006-12-04T11:50:45.251+08:00</updated><title type='text'>SCJP Chapter 1</title><content type='html'>Dealing with access modifiers and visibility of classes, methods and variables. default (package), &lt;span style="font-style: italic;"&gt;public&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;private&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;protected &lt;/span&gt;are the access modifiers with &lt;span style="font-style: italic;"&gt;final&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;static&lt;/span&gt; thrown into the mix.&lt;br /&gt;&lt;br /&gt;Shows correct declaration forms, especially for interfaces and abstract classes. Warns of 'compilable' questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-7650311021542318837?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/7650311021542318837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=7650311021542318837' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7650311021542318837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/7650311021542318837'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/scjp-chapter-1.html' title='SCJP Chapter 1'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-8095914098929214254</id><published>2006-12-04T11:27:00.000+08:00</published><updated>2006-12-04T11:43:11.309+08:00</updated><title type='text'>First day</title><content type='html'>The room is fine, comfortable for one person working. The table takes up a third of the space but on the upside, there's more space to place stuff down. Two extra chairs here that won't see much use.&lt;br /&gt;&lt;br /&gt;For two persons, will need to replace the table with a smaller one or two. Would be a tighter fit at that time.&lt;br /&gt;&lt;br /&gt;Very quiet environment, good for concentration and focus.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-8095914098929214254?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/8095914098929214254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=8095914098929214254' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8095914098929214254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/8095914098929214254'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/12/first-day.html' title='First day'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9098580853969350531.post-5309490338139106446</id><published>2006-11-28T11:56:00.000+08:00</published><updated>2006-11-28T11:58:16.963+08:00</updated><title type='text'>Testing 1, 2, 3</title><content type='html'>First post for Insert Something Creative.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9098580853969350531-5309490338139106446?l=asrijaffar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asrijaffar.blogspot.com/feeds/5309490338139106446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9098580853969350531&amp;postID=5309490338139106446' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5309490338139106446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9098580853969350531/posts/default/5309490338139106446'/><link rel='alternate' type='text/html' href='http://asrijaffar.blogspot.com/2006/11/testing-1-2-3.html' title='Testing 1, 2, 3'/><author><name>Irregular Zero</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
