Monday, May 31, 2010

My $1 Plastic Toy Car has a Metal Flywheel and a Plastic Gearbox

One of the greatest things about being a parent is the ability to relive your own childhood – often vicariously as you watch your own children experience life with fresh eyes. But with toys, we get to experience childhood again firsthand. I believe the electric train and R/C car toy markets exist principally to cater to the fathers rather than the children. I know my dad spent much more time setting up and working the electric train table than us kids. But this is hardly the point of this blog post.

tractor_withtop

Rather, I glimpsed inside a broken toy tonight, and was intrigued by what I could see. I was interested enough to break it open and see exactly how it was put together. It turns out there is some good mechanical engineering principles at work within even the cheapest of toys.

Yellow Tractor from the $1 Bin

In this case, it is a yellow tractor purchased at Target last year for $1. It is the kind of vehicle that you can “rev” up by running it across the table with your hand, and then release and let it move under its own power. My daughter had dismantled pieces from the top, which allowed me to peek inside.

I will provide the model number (Ankyo234041829F16819779-08/09) just in case it is a rare toy that is now worth a million dollars. How about giving me $200,000 for a busted one? As you would expect, you also find Made in China stamped to the bottom.

Inside the toy are the following components:

  • Plastic frame; holes in the plastic serve as bearings for the axles
  • 4 plastic wheels (inside of the fake outer tracks)
  • Metal axles for the wheels, with a spline in the middle to drive the first cog in the drivetrain
  • A gearbox of 3 cogs; the middle cog is actually 2 cogs mated together (small and big). Metal shafts hold the cogs in place.
  • A big metal flywheel (probably lead, to provide for better inertia)

I was surprised at how much mechanical advantage was provided by the gearbox. Moving the wheels just a fraction of a turn spun the big flywheel all the way around. Nice job, Made in China guys!

tractor_gearbox_flywheel

Note: that little green plastic tab is only there to make noise. It rests on top of the flywheel input cog, and gives the gearbox a little clickity click sound as it rakes over the teeth.

The Gearbox

I have time boxed this blog post to less than 45 minutes, because, well, this isn’t something I should be spending a lot of time on. But I did want to understand how much mechanical advantage was being provided by the gearbox. I decided that counting teeth on each wheel was going to take too long, so I am just making some estimates here. Also, I am not rechecking my high school physics text book, so I could be doing this all wrong. Like it matters.

But I estimate the advantage to be 125:1. Meaning, every rotation of the wheel will result in 125 rotations of the flywheel. Imagine what happens when you rapidly move the car across, say 2 feet, of table top. Assuming the wheel circumference is 2 inches, that means the the wheels will spin 12 times, causing the flywheel to spin 1500 times. Holy shrapnel-if-it-disintegrates!

Once again, I am timeboxed. So this diagram is the best I can come up with to illustrate the gearbox design:

tractor_sequence

I came up with my 125:1 figure by estimating three places of mechanical advantage of 5:1. If my physics are right, we multiply those together to get 125. Sorry for wasting 3 minutes of your life if that isn’t right, hey we are all doing the best we can.

Conclusion

Is there one?

Perhaps this is interesting stuff to you, as it was to me. I didn’t think a toy from the $1 bin at Target would reveal a lesson in mechanical advantage interesting enough for me to write about. I was wrong. Sorry, Made in China guys, for underestimating you.

(elapsed time in researching and writing this post – 51 minutes)

Technorati Tags: ,,,

Sunday, May 16, 2010

Browsing your SnapLogic SQLite Configuration Database

This blog post explains how to browse the configuration database of your SnapLogic server. I found this helpful when I was modifying some SnapLogic server code, and messed something up. I thought I had corrupted something in the database (I hadn’t), so wanted to open it up and take a look. I thought I’d share what I learned.

It turns out the SnapLogic configuration repository is really simple. There is only one table you really care about, and it has but a few columns.

Setting Up Your SQLite Browser

The configuration database for SnapLogic is a standard SQLite database. There are various tools you could use to browse it, but I like the Firefox SQLite Manager plugin. It installs into a tool you probably already use (Firefox) and does everything you need.

Steps to get running:

  • Install the SQLite Manager plugin and restart Firefox
  • Navigate to Tools->SQLite Manager in the Firefox menu
    • A new window will popup with the manager in view
  • Navigate to Database->Connect Database in the menu
  • When the file browser pops up, choose your SnapLogic repository DB
    • Choose [SNAPLOGIC_HOME]/repository/repository.db
    • You will have to disable file extension filtering; make sure “All Files” is selected

You should now have the SnapLogic database open for browsing.

Inside the Resource Table

The table of interest is the resource table. It contains the definitions of all of your resources, including component instances and pipelines. Almost everything you do in the SnapLogic Designer UI is stored in this table.

The table has the following structure:

Column Purpose
uri The logical URI given to the resource in the Designer. As in: /SnapLogic/Tutorial/Exercise_5/Resources/SortProspects
guid A nice globally unique id for the instance. For migration/backups, this is very nice to have.
gen_id A version number. Incremented each time you click Save on the resource in the Designer.
object The actual definition of the resource. This is a large field, and is written in a readable format (JSON?).
validated Has this resource been validated? 0 for false, 1 for true. See caveat below.

Overall, it is pretty self explanatory as far as I can tell. Perhaps there are hidden nuances, but none that I have detected.

The only surprise was the use of the validated column. I thought that would be updated when you hit the “Validate…” button in the Designer. Not so, at least in SnapLogic 2.1.0 (beta). This column seems to be updated upon a successful run of a Preview operation.

I hope this blog post helps you in your SnapLogic development. Post a comment if so!

Technorati Tags: ,

Friday, May 14, 2010

Upgrade to Ubuntu 10.04 broke my Postgres – “Could not Connect to Server” in Pgadmin

I upgraded last week to Ubuntu 10.04, and just noticed today that my development environment was broken (yeah yeah, it took a week to notice, give me a hard time about not spending enough time coding). I looked into it, and found a weird problem caused by the upgrade – perhaps if you are reading this you have that problem too. My Postgres database was apparently not operating.

Postgres 8.4 Upgrade

I did notice that the Ubuntu 10.04 upgrade was taking me from Postgresql 8.3 to 8.4. I figured that should be fine. And it is, but it caused some downstream problems.

First off, put away any notion that the upgrade does an automatic migration of your databases from 8.3 to 8.4. Ubuntu is good, but not that good. You will have to manually migrate your databases yourself. I imagine you should dump all your databases before you do your upgrade, as the upgrade does remove 8.3 from /usr/lib/postgresql. Since I could rebuild my databases, I didn’t have to worry about migration – but do some research ahead of time if you do.

This was one issue – my dev databases were not migrated into 8.4. I needed to rebuild them, and recreate our dev user in 8.4. But before I could do that…

Pgadmin Could Not Connect

A major roadblock was that I could not connect to Postgres using Pgadmin, even as the ‘postgres’ user. In fact, I couldn’t seem to get network connectivity to Postgres at all. What is going on?

Server doesn't listen
The server doesn't accept connections: the connection library reports could not connect to server: Connection refused Is the server running on host "127.0.0.1" and accepting TCP/IP connections on port 5432?

To troubleshoot this, I made sure that the processes were running:

sudo /etc/init.d/postgresql-8.4 restart

and then made sure it stayed started:

ps –ef | grep postgres

and also checked the logs:

/var/log/postgresql$ cat postgresql-8.4-main.log

But everything seemed to be kosher. I was also able to use psql from the command line. What is going on, I still can’t connect from Pgadmin? An invocation of netstat is what solved it:

netstat -ln | grep 5432

That should have returned some lines like:

tcp        0      0 127.0.0.1:5432          0.0.0.0:*               LISTEN    
tcp6       0      0 ::1:5432                :::*                    LISTEN    
unix  2      [ ACC ]     STREAM     LISTENING     5623     /var/run/postgresql/.s.PGSQL.5432

but it returned nothing. Eh? 5432 is the default port for postgresql, and the port I use in my Pgadmin connections. It should be there.

I then looked at the postgres server configuration in  /etc/postgresql/8.4/main/postgresql.conf and found the problem:

port = 5433

For some reason the upgrader installed 8.4 on port 5433 instead of 5432. During the upgrade it perhaps needs to run 8.3 and 8.4 at the same time, and therefore puts them on different ports. But after upgrade, shouldn’t it switch 8.4 back to the default port?

Its an easy fix:

sudo gedit postgresql.conf   (change 5433 to 5432)

sudo /etc/init.d/postgresql-8.4 stop

sudo /etc/init.d/postgresql-8.4 start

Note that I first tried just restart, but found that the port change did not take effect. I had to do a stop and start explicitly.

I am now back up and running again with Postgres 8.4. Joy.

Technorati Tags: ,

Thursday, May 13, 2010

Installing SnapLogic Community Edition 2.1.0 on Ubuntu 8.10 in 5 minutes

If you read my last post, you would know that I hit a snag running the community edition of SnapLogic 2.2. There appears to be a hard dependency on a license check (see ticket 2449). Since I have no idea how long that will take to resolve, I decided to find a way around the problem.

I chose to roll back to version 2.1.0. But in doing so, I had some struggles. SnapLogic 2.1.0 is based on Python 2.5.x and related components. My Ubuntu 10.04 install uses Python 2.6.x, and the 2.5.x stuff has been removed from the Ubuntu repositories.

After trying some minor hackery to get P2.5.x on U10.04 (building stuff from source), I gave up at trying to get the dependencies resolved. Instead, I just plopped down a new Ubuntu 8.10 VM on my machine, and got things going pretty quickly.

These are my notes. By the way, the 5 minutes I reference in the title is just for the SnapLogic install. Installing and updating Ubuntu takes about an hour, depending on network speeds.

  • Install 8.10
    • Download a VDI and install into VirtualBox, or
    • Do a bare metal install (e.g. dual boot)
  • Update your OS
    • 368 updates and counting as of today
    • Make sure not to upgrade Python beyond 2.5.x
    • Reboot
  • Download SnapLogic 2.1.0
  • Launch the SnapLogic installer
    • chmod u+x [blahblah.bin]
    • It will inform you what is missing from prereqs
  • Install the missing prereqs
    • Launch Synaptic Package Manager, and install:
    • python2.5-dev
    • libmysqlclient15-dev
    • libxml2-dev
    • libxslt1-dev
  • Rerun SnapLogic installer
    • Accept all defaults
    • Password is password
    • Elect to start up the servers at the end
  • Install Flash Plugin for Firefox
  • Navigate to the Designer UI
    • http://[hostname]:8081/
    • Open the Leads_to_Prospects Pipeline
    • Select the Run tab
    • Run the pipeline (this is where SL 2.2 fails for me)
    • Success!

 

SLDesigner

Technorati Tags: ,,

Building and Installing SnapLogic 2.2 from Source on Ubuntu 10.04

This blog post walks you through building and installing SnapLogic 2.2 on a Ubuntu 10.04 box. These instructions will lead you through building the product from source. There is also a handy installer available, but that is only for the Pro version. The Pro version has a 14 day trial, and then you’ll have to fork over money. Since I plan to work on my prototype over a longer period of time, I have decided to build the community version from source.

Note: there is currently a blocking issue that prevents this from working. Be sure to read through to the bottom of this page for details before proceeding on this yourself.

The official build and installation instructions live on the SnapLogic wiki, but I am posting here so I can provide more details as I go. Also, there are a couple of changes from the official instructions presumably due to 10.04. Since it seems only Ubuntu 9.x is supported for SnapLogic 2.2, updating the official wiki would probably not be welcome. Items marked with DELTA below are different relative to the official docs.

Caveat: I am running 10.04, but my laptop has been a Ubuntu machine since 9.04. I did an in place upgrade to 9.10 and then 10.04, and have installed a lot of things along the way. Your mileage may therefore vary with these instructions.

Step 1: Install Prerequisite Packages (DELTA)

Execute the following command in a terminal window:

sudo apt-get install python-mysqldb python-pysqlite2 python-cherrypy3 python-feedparser python-simplejson python-lxml python-beautifulsoup python-paste python-genshi

Note: make sure to specificy python-cherrypy3, otherwise you get 2.3.0-3, which will not work with SnapLogic 2.2.

Step 2: Download the Source

Go to the community site and download the source for both the server and the designer:

Step 3: Extract the Source into a Directory

cd ~/dev
mkdir snaplogic
cd snaplogic/
unzip /home/plaird/Desktop/downloads/snaplogic-src-2.2.0.zip
 

Step 4: Create a Runtime Directory

cd ~/dev/snaplogic/
mkdir runtime

Step 5: Setup your Shell

Ultimately, you want to define these in ~/.bashrc, but we will do it inline for now.

export SnapPackageDir=/home/plaird/dev/snaplogic
export SnapRuntimeDir=/home/plaird/dev/snaplogic/runtime
export PYTHONPATH=$PYTHONPATH:${SnapPackageDir}

Step 6: Build out your Runtime Directories

mkdir ${SnapRuntimeDir}
mkdir ${SnapRuntimeDir}/bin
mkdir ${SnapRuntimeDir}/repository
mkdir ${SnapRuntimeDir}/designer
mkdir ${SnapRuntimeDir}/cache_dir
mkdir ${SnapRuntimeDir}/compute
mkdir ${SnapRuntimeDir}/static
mkdir ${SnapRuntimeDir}/logs
mkdir ${SnapRuntimeDir}/config

Step 7: Copy in Runtime Files (DELTA)

The official instructions inform you that you need to install icon files at this point. That no longer seems necessary, as the Designer installation in a later step now takes care of that.

However, I found that you do need to install the components and tutorial into the runtime directory.

cd ${SnapRuntimeDir}
cp -r ../snaplogic/components/ .
cp –r ../snaplogic/example/tutorial .
cd tutorial
mkdir data
mv *.csv data

Step 8: Launch SnapAdmin

cd ${SnapRuntimeDir}
python ${SnapPackageDir}/snaplogic/tools/snapadmin.py

Step 9: Create your Repository in the Runtime Directory

repository create -t sqlite /home/plaird/dev/snaplogic/runtime/repository/repository.db

Step 10: Create a Server Configuration File

Download the template configuration file from the website (link is on this page) and copy it into your ${SnapRuntimeDir}/config directory. Make the following modifications:

  • Replace ${SnapRuntimeDir} with absolute path
  • Change YOURHOST.EXAMPLE.COM to the fully qualified domain name of your host (three locations)
  • Optionally change the ports from 8088, 8081 and 8089

Step 11: Install the Authentication Files

These files give you a starting solution for authentication:

cp ${SnapPackageDir}/snaplogic/server/auth/simple_snapaccess.conf ${SnapRuntimeDir}/config/
cp ${SnapPackageDir}/snaplogic/server/auth/simple_passwords ${SnapRuntimeDir}/config/

Step 12: Install the Designer GUI

cd ${SnapRuntimeDir}unzip /home/plaird/Desktop/downloads/snaplogic-designer-2.2.0.zip

Step 13: Create the Server Start Script (DELTA)

The default control script is not included in the community edition. Create a file called startServers.sh in your runtime directory. Its contents should be as follows (replacing localhost:8088 with your server URL):

echo "Starting data server"
python ${SnapPackageDir}/snaplogic/server/server.py  --config=${SnapRuntimeDir}/config/snaplogic_server.conf &
echo "Starting management server"
python ${SnapPackageDir}/snaplogic/mgmtserver/mgmt_server.py --config=${SnapRuntimeDir}/config/snaplogic_server.conf &
echo "Starting component server"
python ${SnapPackageDir}/snaplogic/cc/component_container.py --name=cc1 --server=
http://localhost:8088 &

Step 14: Correct the Bad Import on Ubuntu 10.04 (DELTA)

If you are running with Ubuntu 10.04, you probably have package python-simplejson at version 2.0.9-1build1. SnapLogic 2.2 was certified against version 1.7.1. You will need to remove an import statement from a SnapLogic file:

gedit /home/plaird/dev/snaplogic/snaplogic/rp/streaming_json_rp.py

Edit out this line:

from simplejson.decoder import JSONScanner

Step 15: Start the Servers and View the UI (DELTA)

chmod u+x startServers.sh
./startServers.sh
firefox
http://<your_machine_name>:8081 &

Step 16: Walk through Tutorial

You can at this point start with the tutorials.

Step 17: ROAD BLOCK

Sadly, at this point I have hit a road block. The community edition of the product apparently has a bug in that it depends on an license file for a commercial version of the product (pro or core). I have filed defect 2449 – hope to get a fix shortly!

In the meantime, see my follow on post on how to install SnapLogic 2.1.0 instead. While it is an earlier version, the upside is the 2.1.0 version has a community installer.

 

Technorati Tags: ,,

Thursday, May 6, 2010

Example Linux startup service for Python, Java, Ruby, Perl, or Script as a daemon process in init.d

This blog post provides sample Bash code for converting a Python, Java, Ruby, Perl, C++, script, or any other program as a Linux service that will start running at system startup. It is a script that is deployed in /etc/init.d like many other common service programs.

Note that there may be language specific ways of doing what you want. For example, there is an evolving Python package that is supposed to do this for you. At this writing, that package seems to be still in progress.

This solution has three components:

  • The actual program that needs to run as a service. In this example, it is a python (.py) program. But it really can be anything, including Java, Ruby, C++, or whatever
  • A wrapper Bash script that simply invokes the actual program. The only value add is that it writes the process identifier of the actual program to a file. You could possibly folder this functionality into the daemon itself, but I haven’t bothered to do that.
  • The daemon script. It is what is located in /etc/init.d and ultimately is responsible for starting and stopping the service.

Actual Program – echoHW.py

For this example, it does nothing real. It just spins the process:

import time

while 1 < 2:
    time.sleep(10)

Wrapper Script – echoHW.sh

This script simply invokes the actual program. It does also write out the process identifier to the file.

# Execute the actual python script
# The "$@" passes in any parameters into the python exectuable
# The '&' puts the process into background (as a daemon)
# The 'echo $! > mydaemon.pid'  write the process id to a file

python echoHW.py "$@" &
echo $! > mydaemon.pid

Daemon Script – mydaemon

This file must be copied into /etc/init.d.

#!/bin/bash
#
# mydaemon          Start/Stop any shell script
#
# chkconfig: 345 95 65
# description: mydaemon 
# processname: mydaemond
#

# ENVIRONMENT
# Edit these for your configuration

# Name for the service, used in logging
NAME=mydaemon

# Name of the user to be used to execute the service
SCRIPT_USER=plaird

# Example of how to pass paramters into the command
PARAM2=whatever

# In which directory is the shell script that this service will execute
MYDAEMON_SCRIPTS_DIR=/home/plaird/dev/linux

# Construct the command the will cd into the right directory, and invoke the script
MYDAEMON_COMMAND="cd $MYDAEMON_SCRIPTS_DIR; ./echoHW.sh 'param1' $PARAM2"

# How can the script be identified if it appears in a 'ps' command via grep?
#  Examples to use are 'java', 'python' etc.
MYDAEMON_PROCESS_TYPE=python

# Where to write the log file?
MYDAEMON_SVC_LOG_FILE=$MYDAEMON_SCRIPTS_DIR/mydaemon.log

# Where to write the process identifier - this is used to track if the service is already running
# Note: the script noted in the COMMAND must actually write this file
PID_FILE=$MYDAEMON_SCRIPTS_DIR/mydaemon.pid

# Load system specific optional arguments
# Create and populate this file with machine specific settings
if [ -f /etc/sysconfig/mydaemond ]; then
    . /etc/sysconfig/mydaemond
fi

# Is the service already running? If so, capture the process id
if [ -f $PID_FILE ]; then
    PID=`cat $PID_FILE`
else
    PID=""
fi

# SERVICE ENTRY POINTS (START/STOP)

# Start Command
start() {
    if [ "${PID}" != "" ]; then
        # Check to see if the /proc dir for this process exists
        if [ -a /proc/${PID} ]; then
            # check to make sure this is likely the running service
            ps aux | grep ${PID} | grep $MYDAEMON_PROCESS_TYPE >> /dev/null
            # If it is a process of the right type assume that it is mydaemon and just exit
            # otherwise remove the subsys lock file and start mydaemon
            if [ "$?" = "0" ]; then
                exit 1
            else
                echo "mydaemon lock file still exists, removing..."
                rm /var/lock/mydaemond
            fi
        else
            # The process running as pid $PID is not a process of the right type, remove subsys
            # lock and start mydaemon
            echo "mydaemon lock file still exists, removing..."
            rm /var/lock/mydaemond
        fi
    fi
    echo -n "Starting mydaemon: "   
    su - $SCRIPT_USER -c "/bin/sh -c \"$MYDAEMON_COMMAND > $MYDAEMON_SVC_LOG_FILE 2>&1\"" & RETVAL=$?
    sleep 3
    touch /var/lock/mydaemond
    exit 0
}

stop() {

    echo -n $"Stopping mydaemon: "
    if [ "${PID}" != "" ]; then
        echo -n "killing " $PID
        kill ${PID}
        for i in {1..30}
        do
            if [ -n "`ps aux | grep $MYDAEMON_PROCESS_TYPE | grep mydaemon `" ]; then
                sleep 1 # Still running, wait a second.
                echo -n .
            else
                # stopped
                rm -f /var/lock/mydaemond
                rm -f $PID_FILE
                echo
                exit 0
            fi
        done
    else
        echo "$NAME is not running"
        exit 1
    fi
    echo "Failed to stop in 30 seconds."
    kill -QUIT ${PID} # Request a thread dump so we can diagnose a hung shutdown
    exit 1
}

case "$1" in
  start)
      start
    ;;
  stop)
      stop
    ;;
  *)
    echo $"Usage: $0 {start|stop}"
    exit 1
esac

Installation

1. Start by copying the actual program and wrapper script somewhere on your machine in a permanent location.

2. Next, edit the mydaemon script to reflect the location where the program was installed. You may want to rename the file, and update the name of mydaemon inside the file.

3. Copy the mydameon script to /etc/init.d. As in:

sudo cp mydaemon /etc/init.d

4. Install the service. Installation will vary depending on your flavor of Linux. If you have chkconfig installed, it will be:

sudo chkconfig –-add mydaemon

If you are on a distro like Ubuntu, use update-rc.d, as in:

sudo update-rc.d mydaemon defaults

Service Usage

The service should now start on startup the computer. But you can invoke it manually as root:

sudo service mydaemon start

or:

sudo service mydaemon stop

Technorati Tags: ,,

Friday, April 30, 2010

Sample code for a GWT Popup Anchor that links to an External URL

Do you need to have an anchor on your GWT page that pops up a window that navigates to an external/arbitrary URL? I’m your guy.

I have an easy solution that involves adding a ClickHandler to your anchor. The image below shows the result. After clicking the Redeem Now button (uses my ImageAnchor widget from the previous post), a window pops up and navigates to an external URL.

gwt_popup_external

View.java Sample Code

In your view file, declare your anchor. I use UiBinder so I have the UiField annotation, but you don’t need it if you aren’t using UiBinder.

@UiField
Anchor redeemButton;

Define a JavaScript function in your view:

public static native void popupAnchor(String url) /*-{
    window.open(url, 'Redeem Rewards', 'width=1024,height=900,scrollbars=yes');
    return false;
}-*/;

Create a method that attaches a ClickHandler to your anchor:

private HandlerRegistration updateAnchorClickHandler(Anchor anchor, HandlerRegistration existingClickHandler, final String rewardsURL) {
    // We will be updating the URL from time to time from a Timer
    // Make sure we aren't adding multiple handlers to the same anchor
    if (existingClickHandler != null) {
        existingClickHandler.removeHandler();
    }
    HandlerRegistration newHandler = anchor.addClickHandler(new ClickHandler() {
        public void onClick(ClickEvent event) {
            popupAnchor(rewardsURL);
        }
    });
    return newHandler;
}

Declare a handler registration as a class member variable. This holds on to the ClickHandler’s registration to the anchor. This allows us to remove it in case the popup url needs to be updated.

private HandlerRegistration redeemHandlerRegistration = null;

Finally, whenever you want to assign a new/updated popup URL for the anchor, simply call your method:

String rewardsURL = whatever you want

redeemHandlerRegistration = updateAnchorClickHandler(redeemButton, redeemHandlerRegistration, rewardsURL);

 

 

Technorati Tags: ,

ImageAnchor Sample Code: a GWT Anchor Widget that displays an Image

I needed to create an anchor to an external site in GWT, but display an image in that anchor instead of text. I was surprised this widget wasn’t included in standard set offered by GWT. But it turned out to be an easy thing to implement.

Here’s what it is, as shown in Firebug. It is an anchor that surrounds an image:

gwt_imageanchor

Sample Code

ImageAnchor.java

This class is the implementation of the actual widget. It needs to be in some spot in your project. Note that this implementation assumes you are using the ImageResource facility. You could also provide the image via URL, by adding a setUrl() method to ImageAnchor, and changing the Image() constructor to take a String url.

package com.tendril.ui.components.reward.client.view;

import com.google.gwt.user.client.ui.Image;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.DOM;

public class ImageAnchor extends Anchor {

    public ImageAnchor() {
    }

    public void setResource(ImageResource imageResource) {
        Image img = new Image(imageResource);
        img.setStyleName("navbarimg");
        DOM.insertBefore(getElement(), img.getElement(), DOM
                .getFirstChild(getElement()));
    }
}

UiBinder XML

You don’t have to use UiBinder templating for this. It is optional. But if you are using UiBinder, this is how it goes:

Add the package to your namespaces at the top of the document. I use the rw namespace in my case:

<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
    xmlns:g="urn:import:com.google.gwt.user.client.ui"
    xmlns:rw="urn:import:com.tendril.ui.components.reward.client.view"
    >

Then you can use your widget. For example:

<g:HTMLPanel addStyleNames='{resources.style.redeem_button_div}'>
    <rw:ImageAnchor resource="{resources.redeem_button}"
        ui:field="redeemButton" />
</g:HTMLPanel>

View

You can interact with the widget in your view just like any other Anchor. If fact, for my purposes, I declare it as an Anchor supertype.

@UiField
Anchor redeemButton;

Technorati Tags:

Monday, April 19, 2010

Eclipse hangs in m2eclipse DefaultWagonManager.getRemoteFile

This isn’t a constructive post – I am going to vent about yet another reason I feel the combination of Maven-Subversion-Eclipse-AspectJ is the Bermuda triangle (er, make that square) of Java development.

I hit a hang tonight in Eclipse that comes from m2eclipse. I have seen this before, am irritated and I just want to vent about it.

Our toolset:

  • Eclipse 3.5
  • AspectJ Dev Tools 2.0.2
  • m2eclipse .10.0.2010
  • Subclipse 1.6.10

We have many modules. When I work against trunk, I almost always set Maven to offline mode after doing a full build. I don’t need to be on the tip for what I do.

The reason I evoke Bermuda when referring to this combination is the general unreliability I have when working. Eclipse arbitrarily rebuilds entire projects with a single line of Java changed. AspectJ fails to weave. Eclipse hangs for minutes at a time. On and on. This post is about one cause of the hang issue.

Annoying Hangs in Eclipse

I sporadically get hung up on calls to the Maven repo or Subversion. Eclipse will hang for minutes. I have started to monitor the stack traces, and they are so far they are m2eclipse or subclipse related.

As a good open source citizen, I should really stop what I am doing for half a day when this happens to try and figure out what is going wrong. Better yet, see if anyone else has had the problem and already reported it.

After tonight’s 5 minute hang, I did a search. I found other people with the problem (from 2008), yet no answer.

"Worker-9" prio=10 tid=0x0ab96000 nid=0xdf7 in Object.wait() [0x5eacd000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0xaffea3e8> (a org.apache.maven.wagon.providers.http.JettyClientHttpWagon$WagonExchange)
    at java.lang.Object.wait(Object.java:485)
    at org.eclipse.jetty.client.HttpExchange.waitForDone(HttpExchange.java:134)
    - locked <0xaffea3e8> (a org.apache.maven.wagon.providers.http.JettyClientHttpWagon$WagonExchange)
    at org.apache.maven.wagon.providers.http.JettyClientHttpWagon.sendAndWait(JettyClientHttpWagon.java:245)
    at org.apache.maven.wagon.providers.http.JettyClientHttpWagon.getIfNewer(JettyClientHttpWagon.java:347)
    at org.apache.maven.wagon.providers.http.JettyClientHttpWagon.getIfNewer(JettyClientHttpWagon.java:302)
    at org.apache.maven.repository.legacy.DefaultWagonManager.getRemoteFile(DefaultWagonManager.java:292)
    at org.apache.maven.repository.legacy.DefaultWagonManager.getArtifact(DefaultWagonManager.java:99)
    at org.apache.maven.artifact.resolver.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:247)
    at org.apache.maven.artifact.resolver.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:507)
    at org.apache.maven.repository.legacy.LegacyRepositorySystem.resolve(LegacyRepositorySystem.java:325)
    at org.apache.maven.project.RepositoryModelResolver.resolveModel(RepositoryModelResolver.java:171)
    at org.apache.maven.model.building.DefaultModelBuilder.readParentExternally(DefaultModelBuilder.java:582)
    at org.apache.maven.model.building.DefaultModelBuilder.readParent(DefaultModelBuilder.java:449)
    at org.apache.maven.model.building.DefaultModelBuilder.build(DefaultModelBuilder.java:182)
    at org.apache.maven.model.building.DefaultModelBuilder.build(DefaultModelBuilder.java:117)
    at org.apache.maven.project.DefaultProjectBuilder.build(DefaultProjectBuilder.java:117)
    at org.apache.maven.project.DefaultProjectBuilder.build(DefaultProjectBuilder.java:81)
    at org.maven.ide.eclipse.internal.embedder.MavenImpl.readProject(MavenImpl.java:418)
    at org.maven.ide.eclipse.internal.project.MavenProjectManagerImpl$Refresher.phaseOne(MavenProjectManagerImpl.java:448)
    at org.maven.ide.eclipse.internal.project.MavenProjectManagerImpl.refresh(MavenProjectManagerImpl.java:368)
    at org.maven.ide.eclipse.internal.project.MavenProjectManagerRefreshJob.run(MavenProjectManagerRefreshJob.java:93)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

What am I going to do about it?

I know what I should do. Every time I hit an annoying problem, I should drop what I am doing and try and debug it.

I tried debugging the AspectJ issue, and gave up after a lot of problems getting a working debug environment with matching source files for everything. So I would like to help debug this one, but I just don’t have the desire to fight that again.

There is an easy workaround. I was not on my corporate VPN when this happened. I have only seen this problem when off the VPN. Therefore, I can just log into VPN all the time and the problem is avoided.

But I shouldn’t have to do that. My Maven settings clearly indicate an offline build.

If you are on this page, you must be having this same problem (I don’t have subscribers to this blog). Let me know with a comment. If others are annoyed maybe I will devote some time to debugging.

Technorati Tags: ,

Friday, April 16, 2010

Creating a GWT Popup Window – Sample Code Example for PopupPanel and UiBinder

This post is an easy tutorial for creating a popup window in GWT using the PopupPanel component included in the panel. Its really quite simple, so hopefully it will get you going in just a few minutes.

This screenshot shows what is accomplished in this tutorial:

gwt_popup

This example was built using GWT SDK 2.0.3. It employs the UiBinder templating facility to define the contents of the popup, but you can easily do without UiBinder as well.

Sample Code

Because I am lazy, I am splatting in my code “as is”. This means you need to understand that my popup window is called EEGraphPopup and my main application window is the RewardsView. Otherwise, it should all be self explanatory.

EEGraphPopup.java

Create a new Java file in your client directory. This file holds the code behind your popup panel. Notice it directly extends PopupPanel.

package com.tendril.ui.components.reward.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiTemplate;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;

/**
* A simple popup that displays a EEGraph's information.
*/
public class EEGraphPopup extends PopupPanel {

    @UiTemplate("EEGraphPopup.ui.xml")
    interface Binder extends UiBinder<Widget, EEGraphPopup> { }
    private static final Binder binder = GWT.create(Binder.class);
    public EEGraphPopup() {
      // The popup's constructor's argument is a boolean specifying that it
      // auto-close itself when the user clicks outside of it.
      super(true);
      add(binder.createAndBindUi(this));
    }
}

EEGraphPopup.ui.xml

If you are using UiBinder to define your popup view, create this file in your client directory.

<ui:UiBinder
  xmlns:ui='urn:ui:com.google.gwt.uibinder'
  xmlns:g='urn:import:com.google.gwt.user.client.ui'
>

  <ui:image field='ee_graph' src='consumer_ee_graph.png'/>

  <ui:style>

  @sprite .ee_graph {
    gwt-image: 'ee_graph';
    display: block;
    margin-left: auto;
    margin-right: auto;
  }

  </ui:style>

  <g:HTMLPanel styleName='ee_graph_popup'>
      <span>Baseline Energy Usage</span>
    <div class='{style.ee_graph}'/>
  </g:HTMLPanel>

</ui:UiBinder>

rewards.css

Put this stuff in your application’s CSS file.

.ee_graph_popup {
    background: #dfefc8;
    border: 1px solid #808080;
    padding: 0.5em;
    width: 650px;
    height: 400px;
}

RewardsView.java

This code belongs in the view that triggers the popup. I trigger mine via a button ClickHandler. Notice how the line that centers your popup. Also, setGlassEnabled dims the rest of the screen – a very nice feature!

public void onClick(ClickEvent event) {
    EEGraphPopup popup = new EEGraphPopup();
    popup.setGlassEnabled(true);
    popup.center();
    popup.show();
}

References

This post was made possible by a couple other blog posts. Check in with these too:

Technorati Tags: ,

Thursday, April 15, 2010

Sample code for GWT TabLayoutPanel - overriding the default CSS styles

If you are lucky like me, you have a designer who creates your screen mockups for you. This is great, because I suck at creating roundy-border type stuff that actually looks good on a web page. Its all great, until you have to figure out how to build the stuff they design.

This post is about styling a GWT TabLayoutPanel in a way that will make your designer friend happy. Well, as much as one of those guys can ever  be happy.

Here is what I have built. Notice how the tabs are styled – much better than the default styles you get out of the box.

gwt_tabcontrol_css_styled

This sample uses the GWT SDK 2.03. It employs UiBinder, but this technique can be used without it as well.

Approach – Build a Custom Theme

There are references out there that indicate that you may be override the default GWT styles in your own custom CSS stylesheet. They seem to indicate that this will take precedence over the styles defined by the CSS in the standard theme.

I never got that to work, as I could see in Firebug that the theme CSS files were loading later than my custom CSS file. No matter how I rearranged in the includes in my HTML file.

So I took a different tack – I created a custom theme based off of a standard theme. Upon creating the custom theme, I changed the default styles for tab controls. This approach was both easy and effective. Note that it won’t work well for cases in which you have multiple tab controls in your project and need to style them differently. You will need to something with adding styles – details for which I don’t have.

For reference, you can find some links out there on creating custom themes. I used the official GWT docs for this, and they were good:

Sample Code

The code below shows the different snippets required to make this happen.

Theme CSS

I will not include everything you need here, as you will use a standard theme CSS as your base for working. Do a search in the SDK to find the base theme you want – standard.css, dark.css, or chrome.css. For Eclipse users, the SDK is found in a location such as:

eclipse/plugins/com.google.gwt.eclipse.sdkbundle.2.0.3/gwt-2.0.3

Once you find your base CSS, copy it into your war directory in your project. Open the file, and search for the Tab styles. Beyond this, it is an exercise in CSS and Firebug to get your tabs looking exactly how you need. For me, mine are defined like this:

.gwt-TabLayoutPanel
{
    height: 300px;
}

.gwt-TabLayoutPanel .gwt-TabLayoutPanelTabs {
}
.gwt-TabLayoutPanel .gwt-TabLayoutPanelContent {
  border-color: #e6e7e8;
  border-style: solid;
  border-width: 3px 2px 2px;
  overflow: hidden;
  padding: 6px;
  background: #FFFFFF; 
}
.gwt-TabLayoutPanel .gwt-TabLayoutPanelTab {
  margin-left: 6px;
  padding: 3px 8px 3px 8px;
  cursor: pointer;
  cursor: hand;
  color: black;
  font-size: 1.2em;
  color: #8bc53d;
  text-align: center;
  background: #458818;
}
.gwt-TabLayoutPanel .gwt-TabLayoutPanelTab-selected {
  cursor: default;
  background: #8bc53d;
  font-size: 1.2em;
  color: #FFFFFF;
}

Configure Theme in Rewards.gwt.xml File

Find your *.gwt.xml file, usually in the top level directory of your packages. In here, you will need to disable any standard theme you are using, and inherit the basic CSS style objects into your project. Check the reference in the GWT docs listed above for more info.

<!--  <inherits name='com.google.gwt.user.theme.standard.Standard'/>-->
<!--  <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
<!--  <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->
<inherits name='com.google.gwt.user.theme.standard.StandardResources'/>   

Include Custom Theme in Rewards.html

Next, add in your theme’s css file into your UI by including it in the host page. Your html file will be in your war directory. Update it to include your custom .css file, like:

<link type="text/css" rel="stylesheet" href="rewards.css">
<link type="text/css" rel="stylesheet" href="tendril_theme.css">

UiBinder Page

The next thing to do is actually define your TabLayoutPanel in your UI. I use UiBinder for this, but you can do this programmatically as well. Notice that I don’t declare style info for the tab widgets – they automatically consume the custom theme styles.

<g:TabLayoutPanel ui:field="programsTabPanel" barHeight="2" barUnit="EM">
    <g:tab>
        <g:header>Available</g:header>
        <g:HorizontalPanel styleName='program_tab'>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                    CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
    <g:tab>
        <g:header>Demand Response</g:header>
        <g:HorizontalPanel>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                    CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
    <g:tab>
        <g:header>Energy Efficiency</g:header>
        <g:HorizontalPanel styleName='program_tab'>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                   CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
</g:TabLayoutPanel>

Now, the next time you refresh the browser your tabs should look pretty.

Technorati Tags: ,,,,

Code sample for making GWT TabLayoutPanel tabs visible and invisible

Here are some code snippets for making TabLayoutPanel tabs visible and invisible. I use it to provision all my tabs in a UiBinder template up front, but have only those tabs that are relevant visible. This requires me to immediately make most of the tabs invisible on load, and then triggering their visibility when the user takes certain actions.

Use Case

The initial rendering of the tabs looks like this. (if you want to know how I styled the tabs, see another post of mine) Notice only one tab is visible:

gwt_tabcontrol_initial

After the user clicks on one of the enroll buttons, I make the associated tab visible on the control, which results in this:

gwt_tabcontrol_visible

Sample Code

The following is the sample code that I use to make all of this happen.

UiBinder Page

Here is a snippet from my RewardsView.ui.xml UiBinder file, with most of the user text redacted for brevity. Notice how I define all of the possible tabs up front:

<g:TabLayoutPanel ui:field="programsTabPanel" barHeight="2" barUnit="EM">
    <g:tab>
        <g:header>Available</g:header>
        <g:HorizontalPanel styleName='program_tab'>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                    CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
    <g:tab>
        <g:header>Demand Response</g:header>
        <g:HorizontalPanel>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                    CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
    <g:tab>
        <g:header>Energy Efficiency</g:header>
        <g:HorizontalPanel styleName='program_tab'>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                   CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
</g:TabLayoutPanel>

Hiding a tab during initialization of the UiBinder Composite

I then set most of my tabs to invisible during construction of the UiBinder composite. Notice that I had to introduce an extra getParent() call to do this. If you don’t do this, you will find small slivers of the invisible tabs still visible (and still clickable by the user!). Making the parent invisible properly obscures the whole thing.

@UiField TabLayoutPanel programsTabPanel;

public RewardsView(String firstName) {
    initWidget(uiBinder.createAndBindUi(this));
    programsTabPanel.getTabWidget(1).getParent().setVisible(false);
    programsTabPanel.getTabWidget(2).getParent().setVisible(false);
}

Its a bit lame that I reference the tabs by index, but it works for me.

Displaying a hidden tab in a button ClickHandler

Look at the StockWatcher sample if you need to learn how to create a ClickHandler for a button. You could also trigger visibility of a tab via other means. But in the end, you need a line of code like this to make the tab visible again:

programsTabPanel.getTabWidget(2).getParent().setVisible(true);

You will need to determine the right tab index to enable (I show 2 above), but otherwise its a piece of cake. Done!

Technorati Tags: ,

Friday, April 2, 2010

Solution: Mouse disappears when using Skype Share Desktop in Windows VirtualBox VM on Ubuntu Linux Host

That’s a mouthful. But I have an easy solution to this annoying problem. It happens when I run Skype in a Windows VM, and then opt to share desktop. The mouse will disappear, which makes for a tough time navigating around.

This is my configuration:

  • Host OS: Ubuntu Linux 9.10 (with all updates)
  • Guest OS: Windows XP SP3 (with all updates)
    • Guest additions have been installed
  • Hypervisor: VirtualBox 3.1.4
  • Skype: Windows version 4.2.0.155
  • Hardware: Dell Latitude E6400

Solution

Is simple. When I installed

guest additions, it enabled a feature called “Mouse Integration”. It is enabled by default. However, with Skype it causes this mouse problem.

For the duration of your Skype call, simply disable Mouse Integration and this problem goes away. Do this from the VirtualBox menu bar for your VM:

  • Machine –> Disable Mouse Integration
Technorati Tags: ,,

Saturday, March 27, 2010

Solutions to VPN Problems with Ubuntu Linux – vpnc, network-manager, “terminated by dead peer”, WICD

I have been successfully using the Linux vpnc client to connect into the corporate network for months. However, I recently gained access to a more secure VPN network at the company, and I had nothing but trouble. This blog post explains the solution for that, as well as some other random network issues I was having.

Will this blog post solve MY problem?

I don’t know if I can help you, but here are the symptoms I was having on my machine:

  • I could establish VPN, but something truncated my connection every 5 minutes
  • After establishing VPN from certain locations, I could not ssh to my target instance; it never resolved the IP address
  • As I moved around the building (particularly up and down stairs), I had trouble with re-establishing network
  • I found the network hanging every 2 minutes for a few seconds

Troubleshooting

The key to solving these problems is to look into /var/log/syslog. Do you see either of these entries?

"connection terminated by dead peer detection”

This will be noted when something terminates your VPN connection"

“Roamed from BSSID 00:0F:61:1B:A4:32 (ESSID) to (none) ((none))”, followed by “Roamed from BSSID (none) ((none)) to 00:0F:61:1B:A4:32 (ESSID)”

This will happen every 2 minutes, and will be associated with a pause in your network traffic.

network-manager was the problem for me

I believe the source of all the trouble was the second error noted above. Based on Google searches, this indicates that the network card is scanning for new wireless networks every 2 minutes. During this time (which lasts 6 seconds) no other network traffic can be sent. It makes sense that this would cause issues with a picky VPN.

See this Ubuntu bug report for a full explanation (and confusion as to the proper fix) related to this nasty problem. Some folks indicated the network-manager component to be the source of the problem. network-manager is the default network manager for GNOME Linux distros (like Ubuntu). The problem reported in the bug report does not affect everybody – only some network cards. I run on a Dell Latitude E6400 with an Dell 1510 network card.

Sadly, the network-manager folks didn’t agree that it was their problem. So I had to look elsewhere for a solution.

WICD was the solution for me

Following guidance from others posting on the bug report, I uninstalled network-manager and installed an alterative called WICD (pronounced “wicked”). I have been running WICD for a week, and I am sold. All of the issues that I reported are now gone.

WICD has much of the same functionality of network-manager, but is a bit simpler which perhaps is its strength. Here is a screen shot of the WICD applet:

wicd_applet

If you wish to go this route (highly recommended!), issue the following command. It will install wicd and remove network-manager:

sudo aptitude install wicd

Note that wicd doesn't currently (as of 1.6.1) have menu driven support for VPNs. It is supposed to come with version 2.0 though, so keep checking in on this. It simply means that to start a VPN connection, you will have to do it from the command line instead of from the applet. If you are using vpnc, that means you have to do this from a terminal:

sudo vpnc

WICD Pro Tip

One thing that should be the default in WICD, but isn’t, is to always show the wired network connection in the list. Choose this by checking the box in the UI here:

  • Preferences->General->Always show wired interface

Eclipse missing from JPS (Java Process Status) command results list

It has been a while since I have posted. I have been working on some interesting stuff, but somehow didn’t manage to post about it. I will start to correct that.

I had a lot of work to do leading up to this past week. I had a couple of demos due for a big trade show at work. I hit a lot of bumps in the road due to infrastructure problems. I made a list, and I am working through them now that the deadlines are over. The next few posts will probably be about solutions to those.

The one covered here is pretty lame, but I’ll post it anyway.

Java Process Status command

I use the Java Process Status command line tool enough to want it to work perfectly. But, by default, it doesn’t. After launching Eclipse, I would execute JPS and get results like this:

plaird@plaird-laptop:~$ jps
18589 Jps
18339

If I launched multiple copies of Eclipse with different workspaces, I would predictably get:

plaird@plaird-laptop:~$ jps
19369
18339
19388 Jps

This isn’t a big problem, but its annoying. I put it on the list, and looked into it tonight. The reason is simple, and so is the solution.

JPS only works when using the standard Java launcher

The clue comes from the JPS documentation. It states:

The jps command uses the java launcher to find the class name and arguments passed to the main method. If the target JVM is started with a custom launcher, the class name (or JAR file name) and the arguments to the main method will not be available.

Well, that explains it because as many people know…

Eclipse uses a custom (native) launcher

After installing Eclipse, you are provided with a handy executable in the Eclipse directory. Invoking this thing launches Eclipse. Under the hood, it uses platform specific code to make it happen. The main benefit for doing this is to ensure that Eclipse is contained within a single OS process. The native code launches the JVM within its same process using a custom launcher. This appears to be a problem, but…

There is a way to use the standard launcher for Eclipse

However, you can revert to using the standard launcher. As per the launcher docs, there are several ways to do this. The way I chose is to make sure my eclipse.ini has these lines:

-vm
/usr/lib/jvm/java-6-sun-1.6.0.16/bin/java

Since the path for the vm arg is the standard Java launcher, it uses that instead of the custom launcher. Now look at my JPS results:

plaird@plaird-laptop:~$ jps
19369 org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar
18339 org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar
19388 Jps

Problem solved. Well…

Caveats

Sadly, this doesn’t solve the problem of identifying which workspace is in use by either. But as long as you remember the order in which you started them, in most cases the pids will be in order.

And the known downside of multiple processes is evident in a ps –ef command:

18325     1 /bin/sh /home/plaird/Apps/eclipse35/eclipse.sh
18326 18325 /home/plaird/Apps/eclipse35/eclipse
18339 18326 /usr/lib/jvm/java-6-sun-1.6.0.16/bin/java equinox.launcher.jar

20111     1 /bin/sh /home/plaird/Apps/eclipse35/eclipse.sh
20112 20111 /home/plaird/Apps/eclipse35/eclipse
20128 20112 /usr/lib/jvm/java-6-sun-1.6.0.16/bin/java equinox.launcher.jar

Which is worse – JPS not listing Eclipse or having more goo in a ps listing?

Random Footnote

I noticed this comment in the JPS docs:

The lvmid is typically, but not necessarily, the operating system's process identifier for the JVM process.

This means that the pid/lvmid reported by JPS cannot always be used in a kill command. Good to know.  

Technorati Tags: ,

Thursday, January 14, 2010

Building a Custom Ubuntu Linux Kernel on a Dell Latitude E6400

I am now running on a custom build of the 2.6.31.6 kernel. I haven’t made any source mods yet, but I am now armed and dangerous. This post will cover what I had to go through.

More or less, I had a smooth experience aside from one bug. I will try and recap what I did. I didn’t take notes, so this list comes from looking back over the reference guides. There may be some things missing, sorry.

1. Found a few good references

2. Download the source

  • I used Synaptic to get a source archive instead of going with Git
  • I grabbed linux-source-2.6.31

3. Unpack the source into ~/dev/linux-source-2.6.31

  • cp /usr/src/linux-source02.6.31.tar.bz2 ~/dev
  • cd ~/dev
  • tar xjf linux-source02.6.31.tar.bz2

4. Grab a whole mess of dev stuff

  • sudo apt-get install fakeroot kernel-wedge build-essential makedumpfile
  • sudo apt-get build-dep linux
  • I didn’t take good notes, but I remember having to grab more things. You’re on your own, kid.

5. Create a kernel config file using the current as a base

  • cp /boot/config-[whatever] ~/.config

6. Run menuconfig

  • cd ~/dev/linuxwhatever
  • make menuconfig
  • Note the instruction on turning off “Kernel hacking” –> “Compile the kernel with debug info”

7. Gets me some compiler go fast

  • export CONCURRENCY_LEVEL=3

8. Compile, and then wait

  • fakeroot make-kpkg --initrd --append-to-version=-plaird kernel-image kernel-headers
  • Be sure to replace plaird with something meaningful to you
  • This took about 30 minutes for me
  • It puts two .deb files into the parent directory (~/dev)

9. Install the kernel, unsuccessfully

  • sudo dpkg -i linux-image-xxx_i386.deb
  • sudo dpkg -i linux-headers-xxx_i386.deb

This should have worked, but there currently is a weird bug in dkms that affects folks with nvidia graphic cards:

run-parts: /etc/kernel/postinst.d/nvidia-common exited with return code 20

10. Find fix for Bug #292606

It turns out this bug is known, and there is a fix. Since it took the devs a while to figure out the solution, there were some dead ends before I found the right fix.

  • sudo gedit /etc/kernel/postinst.d/kernel_postinst.d_dkms
  • add ‘> /dev/null’ after ‘start dkms_autoinstaller KERNEL=$inst_kern’

11. Install the kernel, successfully

Rerun step 9.

12. Make sure /boot/grub/menu.lst has an entry for your new kernel

  • The install process might have already done this if you haven’t manually modified menu.lst (I had)

13. Reboot and enjoy

  • Armed and dangerous.

Diagnosing slow system start time on Linux with Bootchart

I am probably the last one to this party, but I found this to be cool enough to post.

While my Ubuntu isn’t Windows slow, it is starting to get a bit pokey on startup. I have installed a lot of crap, but most are apps and libraries which shouldn’t affect start time.

I wasn’t actively looking for a solution, but saw mention of Bootchart and thought I’d give it a quick whirl. Its a nice tool. It not only collects data on where time is spent on boot, but it graphs it in a really nice chart.

The reason I think I might be the last to the party on this is that Bootchart has been around for some time – since 2005. It has had time to polish and it is sweet.

In a nutshell, you install it on your machine. It installs itself early on into the init.d chain, and then monitors /proc to see what’s cooking. It collects data on disk usage and CPU usage. Once booted, it then renders a nice image of the boot sequence into /var/log/bootchart.

Below is a snapshot of my boot (hmmm, that’s probably a NSFW statement in some countries). It takes about a minute. I didn’t find anything totally whack on my machine. The main area of optimization would be to not have Postgres start on boot. But, its only about 5 seconds, and I do use it, so I don’t think I am going to do modify that.

Another suspect is Ubuntu One, which is a Dropbox style file sync utility. Its even tech fanboy compatible – you can see that it launches couchdb. I rely on this for my backup strategy, so its an easy decision to keep this one too.

OK, so here it is.

plaird-laptop-karmic-20100114-6