Archive for the ‘Development’ Category

Rewriting REMITT, the J2EE Way

For those people who are unfamiliar with my programming ventures, I had written a three stage extensible billing system a few years back called REMITT (which stands for REMITT Electronic Medical Information Translation and Transmission). I had created the majority of the code in about a week and the XSL transforms required for it to function in another two weeks or so.

Since then, the project has been somewhat languishing, due to it being written in Perl, which is a minor pain to get running for most people on a good day, compounded with it using XML-RPC with sessions as a remote procedural call dialect.

I decided to embark on a complete rewrite of the core of REMITT to make it more portable, more extensible, better designed and far more stable than it had been in past. I have gotten about 3/4 of the way through rewriting the core of REMITT as a J2EE application using MySQL as a database backend. There are a number of improvements I have been working on, including:

  1. True crossplatform nature. – Being J2EE, you can even run it on *shudder* Windows if you felt the need to. I wouldn’t recommend it, but you could do it.
  2. Better threading model. – Instead of a single executor thread pool, each stage of transformation gets its own pool, maintained and reaped by a single control thread. As Java has a very nice threading model, this was much easier than I had anticipated.
  3. Transport scripting. – Instead of requiring heavy-duty programming expertise to write transport plugins, I moved to using Rhino do do embedded Javascript scripting for them, as well as allowing SFTP transport.
  4. Namespaced configuration. – Each user can have their own configuration *per* plugin, which is a lot easier than before. It also has the ability for each plugin to present its configuration options to a frontend, so there’s no more worrying about configuration variable names.
  5. SOAP. – I’m using CXF for web services, and it took me all of a second to generate a proxy class using wsdl2php which worked perfectly the first time around.
  6. Web Interface. – Through the magic of JSP, the REMITT server has its own set of administration pages and monitoring functions, so it’s not quite as much of a black box as before.
  7. IDE Support. – Eclipse is a beautiful IDE, and with Javadoc completion support, makes anything I could have used with Perl look like crap. ‘Nuff said.
  8. OO Model. – Perl OO is to Java OO as a Pinto is to a Tesla Roadster. This thing actually has some architecture behind it. It’s about time.

I’ll be posting the code into REMITT’s SVN trunk shortly, as soon as I’m positive that it does *something* in case anyone else feels the need to work on it. In the meantime, I’ll continue to play with it until I get something useful out of it.

Trixbox directory with Cisco Phones

In case anyone may want to use Trixbox with Cisco 79xx phones and wants to use a directory with it, I have put together a hack to deal with the directory services, which nominally require SugarCRM, so that they report simple extensions back in the appropriate format.

1) In the Endpoint manager, make sure that the services URL and directory URL are in the default configuration for Cisco phones, and restart any phones which are running to activate the configuration.

2) In /var/www/html/cisco/services, make sure that index_cisco.php is symlinked to index.php

3) In /var/www/html/cisco/services/DBConnect.inc, change the default username and password to something with access to the asterisk database, and change the database name to asterisk.

4) Make PhoneDirectory.php in that directory contain:

< ?php

##########################################
# Config section

$Server = "http://$SERVER_ADDR/cisco/services";   # don't add a trailing slash!
$LongDistanceExtension = ""; # change this to match your config

##########################################
#
# Set content type
header("Content-Type: text/xml");

# This is the include file that establishes the connection to the MySQL database
require ("DBConnect.inc"); 

# This sets the offset for the LIMIT portion of the query
$NextStartingRow = $NextSet*30;

# Connect to the database
$ConnectionSuccess = db_connect();
if (!$ConnectionSuccess) exit;

# If the variable "ID" is passed in through the GET string, then display
# extension, phone number and cell phone number for that record with the dial
# key functionality
if ($ID) {
        $PersonDirectoryListing = "\n";

        //$Query  = "SELECT id, first_name, last_name, phone_home, phone_work, phone_mobile, phone_other ";
        //$Query .= "FROM contacts WHERE id = '$ID' ";
        //$Query .= "ORDER BY last_name ";
        $Query  = "SELECT id,description FROM devices WHERE ( tech = 'sip' OR tech = 'iax' ) AND id = '".addslashes($ID)."' ";

        $SelectPersonInfo = mysql_query($Query,$ConnectionSuccess);

        while ($row = mysql_fetch_array($SelectPersonInfo)) {
                $WorkPhone = ereg_replace("[ ()-]+", "", $row['id']);

                $PersonDirectoryListing .= "\n";
                $PersonDirectoryListing .= "Extension:\n";
                //$PersonDirectoryListing .= "$LongDistanceExtension$WorkPhone\n";
                $PersonDirectoryListing .= "$WorkPhone\n";
                $PersonDirectoryListing .= "\n";
        }

        $PersonDirectoryListing .= "\n";

        echo "$PersonDirectoryListing";

# If the variable ID is not passed in on the GET string, then do the
# entire company directory, unless last is passed in. If so then we
# will be using a LIKE filter in our SQL query
} else {
        $PersonNameList = "\n";
        $PersonNameList .= "\n";
        $PersonNameList .= "
Please select one\n";

        $Query  = "SELECT id,description FROM devices WHERE ( tech = 'sip' OR tech = 'iax' ) ";
        //$Query  = "SELECT id, first_name, last_name, phone_home, phone_work, phone_mobile, phone_other ";
        //$Query .= "FROM contacts WHERE deleted = 0 ";

        # If we are searching by last name the add this filter to the query
        if ($LastName) { $Query .= "and description like '%$LastName%' ";  }
        $Query .= "ORDER BY id ASC";

        # If this is the first page of the company directory then we will display the first 30
        if (!$NextSet) {
                $Query .= " Limit 0,30";
        # Now for each subsiquent call we get the next 30 records.
        } else {
                $Query .= " Limit $NextStartingRow,30";
        }

        # Execute the query
        //echo $Query;
        $SelectNameList = mysql_query($Query,$ConnectionSuccess);

        # Count the number of rows returned. This is important because if a full 30 are returned
        # we will display a more option

        $NumberOfRows = mysql_num_rows($SelectNameList);

        if ($NumberOfRows >= 30) {
                $NextSetValue = $NextSet+1;
        }

        # Parse through the query and set up the menu items.
        while ($row = mysql_fetch_array($SelectNameList)) {
                $PersonNameList .= "
\n";
                        $PersonNameList .= "";
                                $PersonNameList .= $row["description"];
                                if ($row["first_name"]) $PersonNameList .= ", " . $row["first_name"];
                        $PersonNameList .= "\n";
                        $PersonNameList .= "";
                                $PersonNameList .= "$Server/PhoneDirectory.php?";
                                $PersonNameList .= "ID=";
                                $PersonNameList .= $row["id"];
                                $PersonNameList .= "\n";
                $PersonNameList .= "\n";
        }

        # If we set NextSetValue above then we will display the more option. Which sets NextSet
        if ($NextSetValue) {
                $PersonNameList .= "
\n";
                        $PersonNameList .= "MORE\n";
                        $PersonNameList .= "$Server/PhoneDirectory.php?NextSet=$NextSetValue\n";
                $PersonNameList .= "\n";
        }
        $PersonNameList .= "";
        echo "$PersonNameList";
}
?>

haproxy 1.3.15.8 and 1.3.16-rc1 for NSLU2

I have packaged up haproxy for the newest released versions as of today for the Linksys NSLU2.

Stable: http://www.mediafire.com/file/bmhtdnzndu2/haproxy_1.3.15.8-1_armeb.ipk
RC: http://www.mediafire.com/file/dmdynmtdjdm/haproxy_1.3.16-rc1-1_armeb.ipk

WRT54G Toolchain

I pulled the mipsel toolkit for the WRT54G from the 180+ MB kit from Linksys for easy access.

hndtools-mipsel-linux-3.2.3.tar.bz2
hndtools-mipsel-uclibc-0.9.19.tar.bz2

haproxy 1.3.15.3 for NSLU2

The only haproxy load balancer package for the NSLU2 is really, really old, and is installed as “optware” in /opt. With that in mind, here’s the 1.3.15.3 package, installed in root.

Package : haproxy_1.3.15.5-2_armv5b.ipk
Source : haproxy-1.3.15.5.tar.gz

urlencode for NSLU2

Instead of having to deal with an entire Perl installation on an NSLU2, I compiled a readily available urlencode binary, which takes piped input and encodes it for use in a URL.

Tarball : urlencode-armv5b.tar.gz

remserial binary for NSLU2

For all those fans of the venerable NSLU2 (or “slug” as we like to call it), I have another package for OpenSlug/BE. This time it’s remserial, a Linux equivalent to the BSD “netfwd” software, allowing serial ports to be redirected over TCP.

Package: remserial_0.2000-1_armv5b.ipk
Source: remserial.tar.gz

For those enterprising people who would like to use my armv5b-softfloat-linux cross compilation toolchain, I have made it available on mediafire as well. It was compiled with Ubuntu 8.04.1 i386, so that’s the safest bet to use for compilation. I had used the NSLU2 “master makefile” to build it, since the vanilla crosstool had provided me little in terms of usable toolchains for the NSLU2.

gmetric binary for NSLU2

Before a friend clued me in to the embedded gmetric project, I had needed to strip out just the gmetric binary for use in monitoring a process on the NSLU2 I was using.

So, for anyone who is interested, I have posted both a binary ipkg package for OpenSLUG/BE and a source package containing all of the pieces I yanked from the ganglia 3.1.1 distribution to create it. (Graciously hosted by mediafire.com…) Hopefully this can be of use to someone.

PERC Controllers and Why Dell Needs a Kick in the Can

This past week, I stumbled on a strange problem with Dell “PERC” RAID controllers in certain rackmount servers, where they would suddenly just stop working for no apparent reason. The nice people at Dell did actually have firmware available for the PERC 3 and 4 controllers to fix this problem, which was pretty nice.

The part that *wasn’t* nice was that they were some stupid Windows binaries which required a floppy disk to be inserted.

First of all, who has a laptop with a floppy drive anymore, and second of all, what if you, like other sane people, don’t use Windows? Thirdly, how often does a floppy disk magically fail to work in a floppy drive?

I ended up doing the following:

  • Create a VirtualBox VM
  • Use dd if=/dev/zero of=floppy.img bs=1k count=1440 to create a floppy image, which I mounted in the VirtualBox
  • “Format” the floppy image in the VM, because apparently Dell’s fuqtard utility can’t write an image to an unformatted disk.
  • Use the stupid utility to write the floppy image.
  • Use mkisofs -pad -b floppy.img -R -o cd.iso floppy.img to create a CD image

Dell, I hate you. Your laptops overheat and suck out loud, and your stupid Windows-only disks and defective RAID controllers bother me. I’m not buying any more of your hardware. You can subsidize Microsoft some other way.

Roving access point

I finally got around to getting a 12VDC power supply for the car (15 USD, cheap!), so my WRT54G3G-ST is mobile, and I got to enjoy trying out Skype while doing 65mph on the Mass Pike.

There’s some sort of gee-whiz factor in all this, but I guess it’s just another way to become more and more endlessly connected.