Thursday, January 31, 2008

Enunciate!

Overview
Starting from scratch to write a web service, getting a WAR built, deployed into JBoss or your favorite container can be a pain. I always start with an existing ant script and project, remove all the existing artifacts, then start fresh. This means, typically, an hour or so of deleting unneeded jars/classes/relics, search-n-replacing, fixing built script to remove any references to the old project-specific crud, deploying to my container to test a simple hello-world-ish app.

I hate doing this "setup" type work. It's boring and lame. .NET makes it really easy to startup a new project, so why do I hate doing it in Java?

So, what options are there for Java? One I have recently run across is Enunciate from our XFire friends at CodeHaus.

Enunciate appears to solve a nice little java pain point -- "How can I rapidly deploy a webservice without bothering with all the infrastructure crud?"

With a few simple JSR 181 annotations, and using enunciate, you can quickly wrap up a complete, deployable WAR which contains a WS-I Basic Profile compliant web service, nice browsable service documentation, client code in the form of a JAR, WSDL, etc.

If it sounds like a lot of effort, don't be fooled. I loosely followed the enunciate Quick Start and had my own simple web service up and running within a few minutes. This included setting up the eclipse project, downloading and unpacking enunciate, creating the ant build script, deploying to JBoss, and playing with the created application.

Let's go through a quick example on setting up enunciate, building a sample project, and deploying it to JBoss.

Enunciate is very module. In fact, all of the default functionality is provided via a set of modules that come with enunciate out of the box. If there is a deployable artifact that you want and there isn't a module for your desired functionality, then you are free to create your own module and donate it back to the project.

Getting Set Up
I'll assume you already have a JDK, IDE, and a container installed. Download enunciate from http://enunciate.codehaus.org/downloads.html. The latest at the time of this post is 1.6, release on January 8, 2008. The download is only 9.2 megs.

Extract the archive to some location. I extracted it to $HOME/bin.

If you want to run enunciate from cmd line versus ant script, then add enunciate/bin to your path. I'm going to walk through setting up enunciate as an ant task.
PATH=$PATH:$HOME/bin/enunciate-1.6/bin
Example Project
My sample project doesn't vary much from the enunciate Quick Start. I just like to try things myself in hopes that I hit something new. The example project I quickly thought of is a music service which will have admin and search capabilities for artists, albums, and songs. It is pretty simple, but just to illustrate the simplicity of enunciate and how it can handle some complexities of a "real-world" example.

My example will have artists who can have zero-or-more albums which can have zero-or-more songs. The service will allow adding relationships and searching.

First, I created the project structure and created the simple directory structure:
src
|----build.xml (I'll be using ant)
|----com
........|----music
................|----api
................|----domain
................|----impl
api -- contains interfaces and exceptions which define the exposed service
model -- contains business models and relationships
impl -- implementation classes for the interfaces

Next, I defined the interface for the service. The service will be simple and define the following operations. Note the @WebService annotation (from jsr-181)

import javax.jws.WebService;

import com.music.model.Album;
import com.music.model.Artist;
import com.music.model.Song;

@WebService
public interface MusicServiceInterface {
public Artist addArtist(Artist artist) throws AlreadyExistsException;
public Album addAlbum(Artist artist, Album album) throws AlreadyExistsException;
public Song addSong(Album album, Song song) throws AlreadyExistsException;
public Song[] searchSongs(String someSearchText);
}

Now create skeletons for Album, Artist, and Song as well as AlreadyExistsException, just to get things to compile. For this example, I'm NOT interested in implementing the actual functionality of a music search service; instead, I am only interested in how we expose a service quickly using enunciate.

Next up is to define the implementation class as follows. Note the reference to the implementation class in the @WebService annotation.

import javax.jws.WebService;

import com.music.api.AlreadyExistsException;
import com.music.api.MusicServiceInterface;
import com.music.model.Album;
import com.music.model.Artist;
import com.music.model.Song;

@WebService (
endpointInterface = "com.music.api.MusicServiceInterface"
)
public class MusicServiceImpl implements MusicServiceInterface {

public Album addAlbum(Artist artist, Album album)
throws AlreadyExistsException {
// TODO Auto-generated method stub
return null;
}

public Artist addArtist(Artist artist) throws AlreadyExistsException {
// TODO Auto-generated method stub
return null;
}

public Song addSong(Album album, Song song) throws AlreadyExistsException {
// TODO Auto-generated method stub
return null;
}

public Song[] searchSongs(String someSearchText) {
// TODO Auto-generated method stub
return null;
}

}

Now I have a compilable, but not-yet-functional application. Let's go ahead and see what happens when we use enunciate to create the WAR artifact and deploy it to JBoss.

I want to use ant for this example, so here's a sample build.xml file that you can modify to meet your needs:

    <project name="music-enunciate-example" default="package">

<target name="init">
<property name="enunciate.home" value="/home/dbreese/bin/enunciate-1.6" />
<property name="jdk.home" value="/opt/java/" />

<path id="enunciate.classpath">
<fileset dir="${enunciate.home}/lib">
<include name="**/*.jar" />
</fileset>
<fileset dir="${enunciate.home}">
<include name="enunciate-full-*.jar" />
</fileset>
<fileset dir="${jdk.home}/lib">
<include name="tools.jar"/>
</fileset>
</path>

<taskdef name="enunciate" classname="org.codehaus.enunciate.main.EnunciateTask">
<classpath refid="enunciate.classpath" />
</taskdef>

</target>

<target name="clean">
<delete dir="dist"/>
</target>

<target name="package" depends="clean,init">
<mkdir dir="dist"/>
<enunciate basedir="src">
<include name="**/*.java" />
<classpath refid="enunciate.classpath" />
<export artifactId="spring.war.file" destination="dist/${ant.project.name}.war" />
</enunciate>
</target>
</project>


NOTE: I ran into an issue where it was complaining about "java.lang.NoClassDefFoundError: com/sun/mirror/apt/AnnotationProcessorFactory". To fix, I had to add jdk.home/lib/tools.jar to my classpath. I literally spent 50% of my time on this sample project trying to fix this stupid little error!

Notice the "artifactId" which is "spring.war.file". This indicates that a fully functional WAR FILE will be created. Another possible value is "spring.war.dir" which is an exploded WAR directory.

Enunciate can also produce FLEX-compatible artifacts.

Build the project by running "ant package".

Once it is successfully built, deploy dist/music-enunciate-example.war to your container. Since I'm using a default instance of jboss, I just copy it into $JBOSS_HOME/server/default/deploy and JBoss will deploy it.

Now, open your browser and hit "http://localhost:8080/music-enunciate-example". You should see the following sample page:



The web page has all the complete documentation, wsdl, and even includes a downloadable client.

Documentation is generated directly from javadocs, so as long as you follow good javadoc practices, the html documentation generated by enunciate will be great.

Customization and Modules

You can provide a configuration file that allows you to personalize URLs, namespaces, package names, documentation pages, etc. The configuration file can be provided in the enunciate ant task with the configFile attribute, or the "-f" cmd line option. It appears enunciate also makes use of a "package-info.java" class for annotations which will drive namespaces, documentation, etc.

Enunciate can be extended with modules. The core functionality of enunciate is implemented with modules. For example, the xfire-client module is responsible for generating the downloadable xfire client. The enunciate configuration file has a section which is used to configure each module. Check out this link for information on the core modules that come with enunciate.

REST
Enunciate can also generate restful services for you. This is accomplished using the "rest" module. (See Constraints enunciate places on exposing REST models)

I want to dive more into how enunciate can help with REST APIs in a future article.

Misc Questions
  1. WTF is "artifactId" in the enunciate ant target? Here's a good link which articulates what is available.

Some things I still want to investigate:
  1. How easily is it incorporated into existing projects?
    It seems that you can easily incorporate enunciate into existing projects, but you'd then have multiple ways of exposing your web services which adds project complexity.
  2. Can it handle WSDL/contract-first development?
    Enunciate is more aimed at code-first approach. Still trying to get mind around it and see if WSDL-First is possible.
  3. How does it incorporate into ant/maven? Easy. Plus, see above for a working ant script using the enunciate task.

Friday, January 04, 2008

Synergy -- Sharing a single keyboard and mouse

Synergy is a nifty little software package I just started using. It hasn't been very active for over a year, but what it provides is EXACTLY what I've needed for a long, long time.

My office desk at home is a corner/L-shaped desk with "hidden" drawers for the keyboard. I hate these hidden keyboards (or at least mine!) because my hand can't fit into the crack to grab the mouse to use it effectively. I do consider myself a fast and efficient typer, but I don't really follow a good form; therefore, reaching into a crevice at an odd angle and trying to get my bearing on a hidden keyboard is quite a challenge.

About the only thing I use my desktop for is for editing my digital photos (Canon 40D, in case you were wondering), editing some simple video of the family, and of course, playing my music from iTunes.

I work at home about 60% of the time and have a nice laptop. There are many times when I want to switch over to my desktop and do a simple quick task such as just changing the song, etc. But I'm lazy and dread scooting back my chair, pulling out the keyboard and mouse, changing the song, and then putting everything back into place.

Solution: Synergy! Synergy allows you to set up screen edges to control multiple other computers. You specify one keyboard and mouse that controls them all. Best of all, it runs on just about any OS, including Mac OS 10.2+.

I run Ubuntu 7.10 Gutsy Gibbon on laptop and Windows, so these steps are more tailored for a linux server, but it looks very trivial to set up a Windows Synergy server, too.

Step 1: Determine which computer will act as the controller ("server" in Synergy)

Step 2: Download and install Synergy on all computers you want to control.
For Ubuntu, it is as easy as "sudo apt-get install synergy"

For Windows, just run the executable.

Step 3: Configure the server
My server will be Ubuntu. The config file is located in my $HOME directory:
$ cat .synergy.conf
section: screens
ulaptop:
desktop:
end
section: links
ulaptop:
right = desktop
desktop:
left = ulaptop
end

What the config file shows is 1) what servers/clients you have and 2) how they fit together.

"section:screens" shows that I have only two computers: my server (ulaptop) and one client (desktop).

"section:links" shows where the displays are located in respect to each other. For example, for my laptop, the desktop is on the right. Vice versa, for my desktop, my laptop is on the left.

To configure a Windows Synergy server, launch Synergy and select the "Share this computer's keyboard and mouse (server)" option and then click the "Configure..." button.

These settings just tell Synergy which edges of which screens will cause transfer of the mouse and keyboard to the other computer.

Step 4: Start the server
For linux, $ synergys

For Windows, launch Synergy and select "Share this computer's keyboard and mouse (server)" option.

Step 5: Start the clients
Specify the IP address of the Synergy server. There is a test mode on the Windows client which will indicate if a successful connection is made.

Step 6: Install synergy client as a service
Optionally, you can click the "AutoStart..." button and configure Synergy as either a log-in service or a system service for Windows clients.

That's it! Took me about 10 minutes the first time I tried it and now LOVE it!

Blogging New Year!

I'm promising myself I'm going to do a better job at blogging and putting some useful, thought-inspiring content out here in 2008.

Gotta get into the practice of doing what I should have been doing for years!

Prior to this posting, you'll find a lot of useless crap; mainly just some notes I took while figuring out things in Linux, Development, etc. I figured I'd jot it down on my personal BLOG. From time-to-time I get an email letting me know it helped someone, but you'll probably find it useless.

We'll start with a quick technical note about Synergy.

Friday, February 24, 2006

Subversion Configuration and Install

1) Install packages


$ apt-get install subversion


2) Create sample repos:


$ svnadmin create /var/svn/home


3) Run as a service:


a) make sure inted is installed and configured


$ apt-get install inetd


$ vi /etc/services and insert:


svn 3690/tcp # Subversion


svn 3690/udp # Subversion


$ vi /etc/inetd.conf


svn stream tcp nowait svn /usr/bin/svnserve svnserve -i -r /var/svn


{the svnowner is the userid, so make sure it exists}


4) Make sure your user-id has write perms to the repos created above by the svn user


Thursday, February 23, 2006

SSHFS and Fuse

Great way to have a secure remote filesystem at home and be able to mount it locally while at coffee shop or at work.


1) Download and install fuse and sshfs from Sourceforge.net


2) ./configure, make, and sudo make install for both fuse and sshfs


3) fuse will install libs under /usr/local/lib, so you must give kernel information on where to find the information by adding "/usr/local/lib" to the end of /etc/ld.so.conf.


4) Update ld cache: sudo ldconfig


5) I had to update /etc/modules to include "fuse" so that udev will re-create /dev/fuse when the module is loaded.


6) mount your remote directory:


$ mkdir thisdir


$ sshfs dbreese@192.168.1.200: thisdir


$ mount


7) Unmount it:


$ fusermount -u thisdir

8) If /dev/fuse issues arrise (doesn't exist or can't write to it):

# mknod /dev/fuse c 10 229
# chmod o+rw /dev/fuse

Friday, December 23, 2005

DNS and the ActionTec Modem

he dhclient3 client runs /etc/dhcp3/dhclient-script can be extended by simply creating your own scripts under /etc/dhcp3/dhclient-*-hooks.d/. Check out the man pages for dhclient-script ($ man 8 dhclient-script) and read the HOOKS section.

What I did was just dropped the following script in as an exit hook, so it is executed after the /etc/resolv.conf is updated.

All this hack does is strip out the 192.168.1.1 crap that really doesn't work anyways.



$ cat /etc/dhcp3/dhclient-exit-hooks.d/check_actiontec_dns
BAD_IP=192.168.1.1
echo `date`: checking dns ordering for actiontec woes
grep ${BAD_IP} /etc/resolv.conf > /dev/null
if [ $? == 0 ]; then
echo removing actiontec dns entry
grep -v ${BAD_IP} /etc/resolv.conf > /tmp/resolv.conf
mv /tmp/resolv.conf /etc/resolv.conf
fi


One thing that may break for you is if you go to another wifi access point that is NOT actiontec and it only has a single 192.168.1.1 dns entry. If it did, then you'd end up with an empty /etc/resolv.conf file! Just use this script as a base....

Thursday, December 08, 2005

QEMU -- Likes and Dislikes

Here are some things I'm starting to notice about QEMU:

COOLNESS:
- Loading and saving state -- CTRL-ALT-2 and use loadvm and savevm
- Snapshots -- Use snapshot mode for when you are ready to do some major testing or upgrading. If all goes well, go to the console and commit changes.

NEEDS-SOME-WORK:
- Clipboard integration b/w host and guest. Doesn't seem to be any at all.
- Mouse captured by the guest. Only way to get out is to hit CTRL-ALT. Minor, but I really liked the way VPC and VMWare integrated after you installed the add-ons.

NOTES:
1) $ qemu -localtime -user-net -m 384 -hda -smb /home/dbreese -loadvm tempsave winxppro.img
Could not open '/dev/kqemu' - QEMU acceleration layer not activated

To fix (http://www.hants.lug.org.uk/cgi-bin/wiki.pl?LinuxHints/QemuCompilation)
# /sbin/modprobe kqemu
# mknod /dev/kqemu c 250 0 # Create the KQEMU device
# chmod 666 /dev/kqemu # Make it accessible to all users

If modprobe gives error, then you may be able to:
# mkdir -p /lib/modules/$(uname -r)/misc && cp ~/qemu-0.7.2/kqemu/kqemu.ko /lib/modules/$(uname -r)/misc && depmod -a

CDROMs and QEMU
Sometimes, you will need to insert another cd into the drive. The behaviour is not good for me because my host OS (Ubuntu running Gnome) grabs and mounts the drive. No matter what I tried (manually unmounting and remounting the drive, etc) I could not get QEMU to see the new disk which I had just inserted. To fix this, hit CTRL-ALT-2 in the guest and type:
qemu> change cdrom /dev/cdrom

And it will unmount and remount the cdrom within the guest.

Dual Boot Windows XP and Linux

I installed Linux first. I left the first partition for Windows. I installed Linux first and then installed Windows XP Pro.

Steps:
1) Partition entire drive during linux install. I created the following partitions:
Partition 1 - ntfs - /dev/hda1 - 10gigs
Parittion 2 - ext3 - /dev/hda2 - I made this just a 512M /boot partition to contain my boot images and GRUB config.
Partition 3 - Logical Partition (LVM) - /dev/hda3 - containing 1 volume group with two volumes: home and root - 68 gigs
Partition 4 - Swap - /dev/hda4 - 2 gigs

The nice thing about using a logical volume is that it can be dynamically sized and resized over time. It supposedly does have a small performance hit, so for servers with lots of disk activity, it needs more investigation.

2) Install Linux.
Easy step.

3) Backup MBR
The MBR is stored on first 512 bytes of your primary drive. To back it up is really easy -- just use "dd". One word of caution, though -- make sure you back it up to a drive that is NOT a Logical Volume. That is, put it on a floppy (or your iPod as I did!). If you do, it is still possible to get it back, so don't worry.

$ dd if=/dev/hda of=/media/ipod/mymbr.bak count=1 bs=512

4) Install Windows.
When installing windows, choose the parition you want to install it on. I've heard Windows only really likes to be installed on /dev/hda1, so that is what I always stick to.

Windows will tromp your MBR, so it will only boot into Windows. No worries, though -- the partition table is still there and your data should be there, too!

5) Restore MBR because Windows is not nice and rewrites it.

To do this, I use Knoppix. Download it for free and burn a cd. You can use just about any bootable linux distro. Basically, it is linux which boots into a desktop with most of the common utilities ever needed. I've even used it as a diskless workstation before and used a 512meg pen drive as my home directory.

Once booted into Linux, just put in your floppy or mount your disk where you backed the MBR up to. Then restore the MBR:

$ mount -t ext3 /dev/hda2 /mnt/hda2 (this was my /boot partition was just an ext3 partition)
$ dd in=/mnt/hda2/mymbr.bak of=/dev/hda count=1 bs=512

Then reboot and you should be back into Linux.

6) Update GRUB to boot Windows.
Once back into your previously installed linux, edit /boot/grub/menu.lst and add the following to GRUB's config to optionally boot into Windows during power on:

title Microsoft Windows XP Pro
root (hd0,0)
makeactive
chainloader +1

Other notes:
When I originally partitioned my /dev/hda1, I set the partition type to FAT32. However, when I installed XP, I formatted it as NTFS. When I did all of the above steps, Ubuntu would not load. It complaied during startup that /dev/hda1's partition type was incorrect and just hung. Seems like it should have continued, but it didn't. In /etc/fstab, I could probably add "errors=remount-ro" to /dev/hda1. Anyways, this is what I had to do to get things all fixed back up.

1) Boot into Knoppix
2) Install LVM support (http://www.knoppix.net/wiki/LVM2) and mount your root partition (or wherever you have /etc mounted on).
3) vi /mnt/myoldroot/etc/fstab and comment out the entry for /dev/hda1
4) Once I was able to boot back into my Ubuntu system, I again edited /etc/fstab and changed the type to NTFS and did a "mount -a" to mount it and check it out.
5) To fsck the filesystem:
fsck -a /dev/VolGroup00/LogVol00 # took a long time

Other LVM links:
http://www-128.ibm.com/developerworks/library/l-lvm2.html?n-l-4121
Channel #lvm on freenode

Emulators

I've used VirtualPC, VMWare, and QEMU. QEMU (with KQEMU accelerator, which you don't want to do without). Here are some notes/issues/resolutions for each:

I use the VM's to connect to my corporate VPN via Nortel's Contivity client.

I also took a brief look at BOCHS, but didn't install it. It seemed that most www chater was all about QEMU.

VirtualPC 2005:
- Sometimes shared folders in the guest would "isolate" themselves and never update, even though the host had modified contents of the shared folders. This was a killer for me because I used the VM to do CVS version control within my VPN and my host as the development environment.
- Known issue was found for VirtualPC after applying service pack that stated VPC doesn't run well on laptops with my intel chipset (P4 Centrino w/ Mobile Technology. The "fix" from Microsoft just ran my PC at full blast to keep the chip from entering power saving modes.

VMWare:
- No complaints. Sometimes the mouse pointer gets hosed up and I have to switch from VM to HOST and back and it clears it up.
- Stable.
- Expensive ($180), which is the killer for me. No way will I remove that much out of my own pocket.
- Linux 2.6 time sync issue (documented below)
- Wireless networking can only use NAT. Appearantly an issue with the Linux drivers, not with VMWare.

QEMU:
- Just installed it on my Linux 2.6 Ubuntu.
- Compiled it from source along with the kqemu performance package.
- First issue -- mouse integration did not work. Solution: export SDL_VIDEO_X11_DGAMOUSE=0 before starting qemu.
- Networking ran out of the box.
- Linux 2.6 time sync issue (documented below)
- As with VMWare, you can only use NAT due to limitation in the Linux drivers.
- Once I get around to configuring my guest to connect to my corporate VPN, I will be very curious to know if/how folder sharing works.
- NAT networking is pretty slick -- it has its own firewall, dns, and dhcp.

Here's my startup script for QEMU:
$ cat runqemu.sh
#!/bin/bash
export SDL_VIDEO_X11_DGAMOUSE=0
qemu -localtime -user-net -m 384 -hda winxppro.img

Linux 2.6 Time/Clock Synchronization issue
I've installed the 2.6 (i686) kernel. Appearantly a setting in the Linux source changed from 2.4 to 2.6 which affects the way a virtual machine keeps up with the correct time. The effect was that the guest's clock ran up to 10x warp speed. You could see this by launching the XP Clock.

This issue mostly seems appearant in Mobile chipsets, not desktops, but I'm not 100% sure. The only way I could fix it was by passing "acpi=off" to my kernel during boot. My GRUB /boot/grub/menu.lst entry looks like this:
title Ubuntu, kernel 2.6.12-10-686 (VM TRIALS)
root (hd0,1)
kernel /vmlinuz-2.6.12-10-686 acpi=off root=/dev/mapper/ubuntuvg-root ro quiet splash
initrd /initrd.img-2.6.12-10-686
savedefault
boot

Now my guest clocks stay in perfect sync. However, power saving features are disabled, which is a bugger.

SIMP for Linux

I've used SimpLite (www.secway.co) for MSN encryption for conversations.
Since I'm running Ubuntu now, I found that Secway also has a Linux
version. http://www.secway.fr/us/products/simpserver/

Simply download, extract to /usr/local/simp and start it up. By
default, it starts a local socks-4 proxy for MSN on port 11863, so you
have to configure GAIM to use that port.

Unlike the Windows client, the server version of SIMP must automatically
create keys for you because I didn't have to do anything.

I created an init.d script as follows to auto start/stop it:


#! /bin/sh

SIMPSERVER=/usr/local/simp/bin
/simpserver
PIDFILE=/tmp/simp.pid

set -e

case "$1" in
start)
if [ -e $PIDFILE ]; then
echo $PIDFILE already exists, not starting server.
exit 1
fi
nohup $SIMPSERVER >/dev/null 2>&1 &
echo $! > $PIDFILE
;;
stop)
kill -TERM $(cat $PIDFILE)
rm $PIDFILE
;;
reload|restart|force-reload)
echo $1 not implemented. just kill and restart it yourself.
;;
*)
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac

exit 0

Ubuntu and Debian Packages

Since Ubuntu is a take-off from Debian, it naturally uses Debians packaging tools such as apt-get, to update and configure your system. You may also use the GUI tool, Synaptics Package Manager.

Here are some useful links and info:
Good info about packages (see CONTENTS for a lot more on using apt* tools): http://www.debian.org/doc/manuals/apt-howto/ch-search.en.html

Update all installed packages:
# apt-get update

Install a package:
# apt-get install some-pkg

See what's installed:
# dpkg -l | more

Query packages:
# apt-cache search someRE*

You can convert an RPM file to a DEB package (or to/from other common formats) by using Alien:
$ alien --to-deb somefile.rpm (will create somefile.deb)

Some other things to mention -- apt* tools use a local "database" to drive what packages are available and where to get them. Read the URL link above to understand how it works and how to keep it up-to-date so you always know what the latest packages are available.

Ubuntu Linux 5.10

Running Ubuntu (Breezy Badger) 5.10 linux on laptop now. So far, it is great. Only thing I had issues with was my display driver. I have an HP/Compaw nw8240 latop with an ATI FireGL v5000 card. I had to go and download the linux drivers directly from ATI's website and install them and all is well now.

I downloaded version 8.19.10. (ati-driver-installer-8.19.10-i386.run)

The GL graphics are very slow (screen savers and most games are extremely slow in repainting the screen), but other graphics such as window movements, etc are very fast.

Need to work on DRI support. Supposedly it gives better results.

VERY IMPORTANT NOTE: I installed KDE and X went back to the flashy screen. Even reinstalling the ATI drivers didn't work. Finally found a configuration utility installed by ATI under /usr/X11R6/bin/fglrxconfig which recreates the xorg.conf file and everything will work!