Friday, 17 September 2010

Atlascamp 2010

I'm heading for my first AtlasCamp in San Franciso. The Agenda is up and the Games are afoot.

First and foremost its going to be awsmoe to meet the growing AppFusions team, things are really starting to take shape, go go go!


It's also going to be great to meet more like minded developers in the Atlassian comunity whoI didn't get the opportunity to meet'n'greet at Atlassian Summit 2010.

There are some interesting Lightning Talks coming up, I intend to present on a plugin thats nearing completion, watch My Profile page!

Gotta go, code to write!

Monday, 17 May 2010

Eclipse workspace mechanic

Why do I need this


Eclipse has a lot of preferences, there are SVN, code format, java runtime locations, maven settings, and on and on. Having to rekey all these things when creating a new workspace is time consuming and a pain. This is one reason I have something like 150 projects in my current workspace! I hoped Workspace Mechanic would help.

Install


I can now start a new Eclipse project and import default configuration with the Workspace Mechanic from google, its Eclipse Public License, and is currently at 0.0.2, so perhaps improvements to come.

I've installed this in Eclipse 3.5, I get a tick in the bottom right corner as I have not setup 'rules' yet.

First impressions


OK, so its rule based, and each rule has to be entered by hand into a config file, for example with Preferences, you'd have to use something like: /instance/org.eclipse.ui.ide/REFRESH_WORKSPACE_ON_STARTUP=false

Well, OK, the structure is there, but TBH Ive got more pressing things to do with my time than chop preferences out of eclipse workspace config files.

Closing thoughts


Hopefully future improvements will add some kind of auto-export or even 'mirror' dumping of entire configurations, which would be a winner, as really I do just want an entire copy of what I currently have, minus all the projects.

Update site


Update site is here

Sunday, 16 May 2010

Alfresco Ubuntu/Postgres install - in a nutshell

I'd known of Alfresco for a couple of years and have even installed it a few time to see what was on offer (versus the likes of Sharepoint), with upcoming projects under the www.appfusions.com umbrella, the Confluence - Alfresco plugin has caused me to see whats new in Alfresco 3.3. The Alfresco Install Guide for the installation is pretty comprehensive, I'm only giving the Autobahn subset:

Installation

The install bundled idea is appealing to some people but perhaps the engineer in me just wants to know what is being installed, where and why. So I opted for the *alfresco-community-tomcat-3.3.tar.gz* download.

Extracting

What could go wrong? Kaboom, instant tarball explosion (ALF-2820 duly raised!), grrrr, and only a little mopping up later, I unpacked the tarball in /usr/local/apps/alfresco-3.3.

Database

I use Postgresql for pretty much everything these days. Getting Alfresco to work is straight forward, just create an alfresco database, alfresco user and set its password to, yea, alfresco.

Getting the database driver, surely I would have a copy around the place, but no, so download that and dump in INSTALL_ROOT/tomcat/lib. As I'm using JRE 1.6, I get the JDBC4 version.

Configuration file changes

Next up we need to tweak a config file located at INSTALL_ROOT/tomcat/shared/classes/alfresco-global.properties. Its annoying to find in a linux .tgz distribution that the properties files have got the windows line ending characters (^M), this can be cured with apt-get install tofrodos, more annoyingly, the names of the binaries in the latest 10.04 Ubuntu have changed, used to be 'dos2unix' and 'unix2dos', now, its 'fromdos' and 'todos', ah well, progress. So to strip the ^M do this from the alfresco install dir:

fromdos ./tomcat/shared/classes/alfresco-global.properties

From the documentation the following need to be applied and overridden:

db.driver=org.postgresql.Driver
db.name=alfresco
db.url=jdbc:postgresql://localhost/
db.username=alfresco
db.password=alfresco
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.query.substitutions=true TRUE, false FALSE

One final tweak to the config file was external storage:

dir.root=/srv/alf_data

Starting up

There is a startup script alfresco.sh, it only responds to 'start' and 'stop' arguments, but thats fine for testing. To startup automatically I did the following:

  • Create a alfresco user.

  • Modify the 'alfresco.sh' script to validate who is running it, prevents user ownership issues, inject the following at the top of the script (after line1)

    ALFRESCO_USER=alfresco
    if [ ! "`whoami`" = "$ALFRESCO_USER" ];
    then
    echo "Alfresco must be run as [$ALFRESCO_USER] user, not as ["`whoami`"] (current user)"
    exit
    fi

  • Use the following startup script, it wraps the a alfresco script, and runs it as that user:

    #! /bin/sh
    ### BEGIN INIT INFO
    # Provides: skeleton
    # Required-Start: $remote_fs
    # Required-Stop: $remote_fs
    # Default-Start: 2 3 4 5
    # Default-Stop: 0 1 6
    # Short-Description: Example initscript
    # Description: This file should be used to construct scripts to be
    # placed in /etc/init.d.
    ### END INIT INFO

    #
    # Please remove the "Author" lines above and replace them
    # with your own name if you copy and modify this script.

    # Do NOT "set -e"

    # PATH should only include /usr/* if it runs after the mountnfs.sh script
    PATH=/sbin:/usr/sbin:/bin:/usr/bin
    ALFRESCO_HOME=/usr/local/apps/alfresco/alfresco-community-tomcat-3.3
    DESC="Alfresco"
    NAME=alfresco
    DAEMON=${ALFRESCO_HOME}/${NAME}.sh
    #DAEMON_ARGS="--options args"
    PIDFILE=/var/run/$NAME.pid
    SCRIPTNAME=/etc/init.d/$NAME

    # Exit if the package is not installed
    [ -x "$DAEMON" ] || exit 0

    # Read configuration variable file if it is present
    [ -r /etc/default/$NAME ] && . /etc/default/$NAME

    # Load the VERBOSE setting and other rcS variables
    . /lib/init/vars.sh

    # Define LSB log_* functions.
    # Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
    . /lib/lsb/init-functions

    #
    # Function that starts the daemon/service
    #
    do_start()
    {
    # Return
    # 0 if daemon has been started
    # 1 if daemon was already running
    # 2 if daemon could not be started
    echo calling start
    start-stop-daemon --chuid alfresco --start --quiet --pidfile $PIDFILE --exec $DAEMON start --test > /dev/null \
    || return 1
    start-stop-daemon --chuid alfresco --start --quiet --pidfile $PIDFILE --exec $DAEMON start -- \
    $DAEMON_ARGS \
    || return 2
    # Add code here, if necessary, that waits for the process to be ready
    # to handle requests from services started subsequently which depend
    # on this one. As a last resort, sleep for some time.
    }

    #
    # Function that stops the daemon/service
    #
    do_stop()
    {
    # Return
    # 0 if daemon has been stopped
    # 1 if daemon was already stopped
    # 2 if daemon could not be stopped
    # other if a failure occurred
    start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
    RETVAL="$?"
    [ "$RETVAL" = 2 ] && return 2
    # Wait for children to finish too if this is a daemon that forks
    # and if the daemon is only ever run from this initscript.
    # If the above conditions are not satisfied then add some other code
    # that waits for the process to drop all resources that could be
    # needed by services started subsequently. A last resort is to
    # sleep for some time.
    start-stop-daemon --chuid alfresco --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON stop
    [ "$?" = 2 ] && return 2
    # Many daemons don't delete their pidfiles when they exit.
    rm -f $PIDFILE
    return "$RETVAL"
    }

    case "$1" in
    start)
    [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
    do_start
    case "$?" in
    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;
    stop)
    [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
    do_stop
    case "$?" in
    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;
    restart)
    #
    # If the "reload" option is implemented then remove the
    # 'force-reload' alias
    #
    log_daemon_msg "Restarting $DESC" "$NAME"
    do_stop
    case "$?" in
    0|1)
    do_start
    case "$?" in
    0) log_end_msg 0 ;;
    1) log_end_msg 1 ;; # Old process is still running
    *) log_end_msg 1 ;; # Failed to start
    esac
    ;;
    *)
    # Failed to stop
    log_end_msg 1
    ;;
    esac
    ;;
    *)
    echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2
    exit 3
    ;;
    esac


  • In /etc/init.d, register the alfresco script to be auto started with
    update-rc.d alfresco start 99 2 3 4 5 .



Other packages


I found stacks in the log like:

Execution result:
os: Linux
command: [./bin/pdf2swf, -V]
succeeded: false
exit code: 1
out:
err: Cannot run program "./bin/pdf2swf": java.io.IOException: error=2, No such file or directory

To fix this, you need to install swfutils, install with 'sudo apt-get install swfutils'.

Starting should now be a matter of /etc/init.d/alfresco start. The default port is :8080

More on usage and integration next time.

Monday, 3 May 2010

Developing a commercial Atlassain plugin

I thought I'd spend a little time walking through my recent experience in developing JDigest, a Notification Digester for the Atlassian Jira issue tracker.

Inspiration


One day I had several people ask me how to reduce their inbox noise from Jira, well, there just isn't anything you can do about that, if you're involved, you get notified. Looking through the open issues against the Jira product (in Jira of course!), I found JRA-1369 in Feb 2009. This was set the seed in my my to develop a solution. The problem with these kinds of things is that you never really know if Atlassian is going to 'fix' it in the near future themselves, making the effort redundant.

Proof of concept


The path to a proof of concept helped me in avoid some wrong turns, initially I thought that providing Jira with a new MailQueue implementation would be what was required, but quickly found it was just an over-complication. The route adopted was to create a custom Event Listener, enabling normal non-issue related email to be mailed direct through the existing MailQueue, and issue-related email to be digested, if appropriate.

Unpicking the default Issue Event handler

Jira currently ships with a 'Default' issue event listener implementation, which is hard coded in several places, the likely reasons were to ensure that the event listener got setup before any issue related activity could occur, so as to not loose events.

Fixing the code to not use the Default issue event listener wasn't too hard, just modifying ConsistencyCheckImpl.java to not specifically check for the default listener, and MailListener.java to fix its read only nature to allow system admins to remove it.

Making source code changes to Jira is not something to be taken lightly and concerned me on two fronts, firstly, requiring potential customers to make source code changes could damage adoption, and second, every customization has to be verified on the next release, and Atlassian release often. Initially I made changes by hand, but after the 20th install I wanted something more repeatable so I wrote a Bash script and made use of Sed to programmatically fix the files. Even though this needed slight tweaks for newer versions it will save time in the long term support of various Jira versions.

In order to help the wary, I prebuilt a pre-modified classes that can be used to overwrite the existing classes.

Since then I've found JRA-19957 which asks if this can be fixed, after all, only system admins can modify listeners, its scheduled for 4.1.x so fingers crossed, that this jiggery pokery can be removed soon.

Initial implementation

Exactly what to persist was interesting, I could either (a) try to persist the actual issue event (and its related required data references) and reconstitute later, in order to render the related email content, or (b) render the email, gut the content and persist the rendered output, meaning the reconstituion later would be relatively simple. The initial implementation used RAM to store the actual issue events as they came in. Of course, this isn't scaleable - on a busy site the memory requirements for this would be prohibitive, but was still useful nevertheless, to prove the theory. Choosing (b) seemed to follow the KISS principle.

Gutting the email in HTML and Text forms, and later reconstituting was relatively easy through a Velocity template, and will enable end-user styling, but did present a problem - users could change their email preferences half way through a digest period, so half would be in HTML and half would be in text, oh dear, sorry about that.

By now something in the order of 4 months part time had passed, but at least I was getting digest emails!

Hunting around, it seemed there were two choices, either make use of PropertySet storage within Jira or extend the Jira Database Schema. The choise wasn't clear cut, on the one hand, PropertySet is already present, if used, would ensure queued digest data would not be lost, would be included in backups etc, on the other hand, using XStream (awesome code) to translate objects and fields into XML (even handling Lists etc) whilst certainly being usable, may represent a performance hit. Fortuantely the versatility of how JDigest can be enabled will give admins some options on reducing that.

Meta Data

The digest data was being stored per-user, also being stored was meta data about priority, issue type and project. A user could, through a user preference page see what was in store for them. In addition to that though, I also wanted to provide Project Leads with an idea as to what issue activity had generated on a per-project basis (thinking of future Flot charting of events by project), and also on a global basis, enabling the system admin to flush all data. So, even more meta data was required. Given I'd already chosen the PropertySet storage mechanism, that meant event more serialization of additional meta-data, all in response to each and every issue event. This could turn out to be the achiles heal in terms of performance for larger environments.

Dynamic UI?

Jira 4.x is going dynamic with jQuery under the hood, so after getting the various views behaving as expected, I wired in jQuery support for all the forum submissions and issue status interactions, allowing a targetted refresh. This mean a raft of Servlets to handle the data without XWork Actions interfering.

What? User want flexibility?

8 months in, I start thinking about user configuration, after all, enabling Digesting globally is great, but what about things that the User decides are hot-topics that need up-to-the-minute delivery? Conceiving a UI that wasn't a massive amount of work led me to the idea of a dynamic table, fortunately, enter DataTables an awsome jQuery library, that can be setup to also use jEditable (example)
to yield a client side single (and even multi value select) table editor with ajax calls to persist data. I shall be contributing back to this project heavily!

Licensing


Wow, I thought I was done, 9 months in and I had a working plugin, but. What to do about licensing? After all, Im trying to get payback for the last 9months of burned evenings and weekends. I looked around and initially couldn't find anything, I was specifically interested in Eclipse tooling, but there was simply no such plugin - aha I though, I could write one? But first I looked around some more, I found a reference to the CustomWare License Creator Plugin but it didnt work for me, looking into the sourcecode I found it was based on TrueLicense (IIRC). So I tookup that challenge and wrote some unit tests to validate what I though was correct operation, mostly successful but I became painfully aware of the lack of automation, so I donned my Eclipse (docs, articles) Plugin hat and wrote the automation I wanted, including a runtime Java Maven2 build enabled project generation facility that would auto create a unit test with necessary byte[] data pre-loaded.

With a nice Eclipse plugin to create per-product licensing projects, a storage system (flat files) to store generated licenses in, and Eclipse editors to allow license retrieval and validation as well as the ability to autogenerate the necessary bootstrap license validation code, I have a really useful and Licensable product.

To obfuscate or to not obfuscate, that is the question


Whatever you do, obfuscation can be bypassed if you put enough effort into it, and thats the point, making it a PITA for anyone to mess with it, and if they are that intent, heck, fair enough. There are routes, perhaps native compilation of certain aspects of the licensing, but really, obfuscation doesnt really solve the problem, just stops people using JAD to dump raw java code out potentially enabling simple bytecode tweaks to void licensing. See this great Javaworld article.

There is a cost to obfuscation, I spent 3weeks or so fine-tuning my use of ProGuard and a maven build plugin proguard-maven-plugin to get to grips with the finessing required. Other steps can also be taken to detect tampering, classes can be fingerprinted, and that data secreted to stop casual modification. All of these measures can be circumvented but again, the point is to make it too much grief to want to do.

The development of the Eclipse licensing plugin, provision of a runtime library for third party use, maveninzing the build added something like 3months (part time!) I have yet to wrap that up as a licensed product as a plugin, and as an Eclipse Rich Client Platform application. It cost me time, but gave a reusable platform that has already had 'best bang for buck' techniques applied.

The build


A repeatable build with no manual tweaks is a must, despite the upfront costs in getting it just so. Being able to just hit go and know that everything that should be done will be done will save time tenfold later. This particular case had quite a complex pom.xml file, containing several plugin executions not considered 'normal'. As its not possible to target the order of plugin execution for a given Maven Lifecycle state, I needed to spread out the sequence of plugin executions at the Lifecycle level, slightly misusing Maven, yet achieving what I needed. Maven3 apparently has this fixed.

Summary


The JDigest plugin is a simple concept but converting into a reality took a fair bit of time, and adding in pesky licensing issues almost doubled development time. Of course, next time, that 50% will be more like 5%, probably. It's been a great learning experience and has set me up nicely for future endeavours, I hope this journey will be interesting to some!

p.s. I'm now affiliated with AppFusions, interesting developments ahead!

Friday, 29 January 2010

Nagios3 / Ubuntu wont send email

Email just wouldn't come. No errors, no log output, nada. Turns out there is a deployment bug, #387069 but the fix hasn't seemingly fed back into Ubuntu 9.04, so for my info:

sudo /etc/init.d/nagios3 stop
sudo dpkg-statoverride --update --add nagios www-data 2710 /var/lib/nagios3/rw
sudo dpkg-statoverride --update --add nagios nagios 751 /var/lib/nagios3
sudo /etc/init.d/nagios3 start

And notifications start to flow...

Wednesday, 30 September 2009

jabberd14 for testing with jira

I'm working on getting a previously developed Jira IM library JIMI (which leveraged the work done in Yet Another IM Plugin) integrated with JEMH. The merge was always on the cards but until JEMH got bright enough to enable comment processing, the usability wasn't there. Now is the time.

With IM support, and an ability to modify issues, it becomes a whole new ballgame, so the old JIMI code is getting the dust blown off.

Current IM features include:
  • Jira configuration for Jabber
  • Additional authentication check, including captcha support
  • access to system info, eg memory usage
  • dynamic execution of arbitrary uploaded beanshell scripts. hmmmm.
Im thinking of future-features such as:
  • watch a project
  • watch a component
  • watch an issue
  • watch a user
  • filters enabling matching of subject/comment text (aking to xyz was mentioned...)
  • of course, modifying issues, eg reassign, change priority, resolve, start progress etc etc.
all doable, in time, question is, what can I get working in the next week :)

Monday, 28 September 2009

Jira, SSL and Gmail, what a faff!

I had cause today to verify correct operation of Jira with Gmail with JEMH. I had enough fun to want to write it down for future reference.

1. So Gmail needs SSL for POP and SMTP
The problem is that in order for Jira (Java actually) to setup even a single SSL connection, it needs to be able to trust the source.

Following the Connecting to SSL services page I recalled the nitty gritty of extracting the Gmail security cert, loading into the JRE cacerts file I remembered. Really usefully I was happy to the the old SSLPoke.class file I wrote to do testing ages ago still available, ironically able to use it to test my setup today! With a JRE now able to talk SSL to gmail, time to setup Jira.

2. Setup Jira
a) POP
Adding a popserver entry, with simple details, host as pop.gmail.com and valid username/password. The SSL bit comes in when setting up the handler
When adding a POP handler, ensure the gmail popserver is selected, the handler has a Uses SSL option, which needs setting true, and the port should be 995.

b) SMTP
Followed Configuring JIRA to send SMTP mail , so modified the config/server.xml file, all seemed fine, but this is where I hit a few snags, the most irritating was "java:comp/env....." not found. Turned out this was due to a space at the front of the " java:", gah, my kingdom for a trim().

I found JRA-12180 , so moved the two jars (mail / activation ) from atlassian-jira/WEB-INF/lib into common/lib. Q: Why isnt this already done as part of the standalone dist? huh.

And yet, it still didn't work. Hmm. So found an Atlassian knowledge base article
that indicated the "mail.smptp.socketFactoryClass" entry in the server.xml file that the earlier page instructed to be added.

Alls well that ends well. Gmail now working as SMTP/POP server over SSL,.

Thursday, 4 June 2009

Exterminating debian packages that wont uninstall

Darn it,
you've install shiny package X that didn't come through the relatively QA'd Ubuntu package archive, you don't want it anymore and try and uninstall, and it all goes south. It doesn't uninstall cleanly and every 10minutes you get an update window telling you that only a partial update is posssible.

I ignored this for a few days but my annoyance grew. In my case, the package in question was db2, which Ive kind of moved away from to Postgres due to simple 'just work dammit' reasons.

Removing with the various dpg optons had no effect. Surgery required.

Scalpel in hand and a probable guess that the dpk 'installed packages' file was in /lib somewhere, I did the following:

find /var -exec grep -H db2exc {} \;

This little beuty scans every file for a substring match and prints the matching filename / line. bingo

Sure enough, the file was /var/lib/dpkg/status, a flick of the scalpel and db2exc was history.

I could have done it properly and fixed the uninstall script, but I was feeling ruthless, one of those rm -rf moments.

Monday, 23 February 2009

Automatically resize the 'family pics' collection for a photo frame

I have a C109D 9" Digital Photo frame, which has a 2GB SD flash card. I thought that would have been enough, but I hit the limit over the weekend. This spurred to to finally figure out how to bulk compress images, and annoyingly, not to just convert them but to convert them in a different place so the originals are available for printing.

Resizing several Gb of images is a tedious job, fortunately there are some nifty tools out there to help. At the core of the process is the imagemagick convert program, the rest is syntactic script-sugar.

I wrote two scripts to do this, the first makes the first set of root folders in the target directory and calls the second to do the heavy lifting of per-root folder processing.

A bug in the photo-frame code meant it hung if it encountered an empty directory (took a while to figure that out), so as a post-process, after the compression process has completed, script1 finds all folders with no files, and adds a default as a workaround.

SCRIPT 1 - create.sh
My top level folders were simply the year, eg 2001 etc.

#!/bin/bash
PICS_HOME=/srv/FamilyPics
COMPRESS_HOME=/srv/compressedPics
cd $COMPRESS_HOME
#rm -rf $COMPRESS_HOME/*
for aDir in `find $PICS_HOME -maxdepth 1 -name '200*' -type d`
do
BASEDIR=`basename $aDir`
#echo Making top level folder: $COMPRESS_HOME/$BASEDIR
mkdir -p $COMPRESS_HOME/$BASEDIR
cd $aDir
find . -iname "*.jpg" -exec $PICS_HOME/compressFile.sh $PICS_HOME $COMPRESS_HOME $aDir "{}" \;
done

#Now fixup empty dirs that break the digital photoframe
PLACEHOLDER="$COMPRESS_HOME/2002/someplace/placeholder.jpg"
DIRS=`find $COMPRESS_HOME -type d`
for aDir in $DIRS
do
FILE_COUNT=`find $aDir -maxdepth 1 -type f |wc -l`
if [ $FILE_COUNT -eq 0 ]; then
echo need to fix dir $aDir : $FILE_COUNT
cp $PLACEHOLDER $aDir/.
fi
done


SCRIPT 2 - compressFile.sh
#!/bin/bash
PICS_HOME="$1"
COMPRESS_HOME="$2"
aDir="$3"
BASEDIR=`basename "$aDir"`
aFile="$4"

#echo "picsHome=[$PICS_HOME] compressHome=[$COMPRESS_HOME] aDir=[$aDir] baseDir=[$BASEDIR] aFile=[$aFile]"

FILENAME=`basename "$aFile"`
RELATIVE_PATH=`echo $aFile | sed -e 's/$FILENAME//g' |sed -e 's/ /-/g' | sed -e 's/\.\///g'`
OUTPUT_PATH="$COMPRESS_HOME/$BASEDIR/$RELATIVE_PATH"
OUTPUT_DIR=`dirname $OUTPUT_PATH`
#echo Making Folder path for output: $OUTPUT_DIR
mkdir -p $OUTPUT_DIR
# echo Compressing $BASEDIR/$aFile to $OUTPUT_PATH
cd `dirname $OUTPUT_PATH`
RAW_FILENAME="`basename $OUTPUT_PATH`"

if [ ! -f $OUTPUT_PATH ]; then
if [ -s "$PICS_HOME/$BASEDIR/$aFile" ]; then

cp "$PICS_HOME/$BASEDIR/$aFile" $OUTPUT_PATH
chmod +w $OUTPUT_PATH

# dd if=$PICS_HOME/jpg.hdr of="$RAW_FILENAME" bs=2 count=1
# echo RAW filename=$RAW_FILENAME
# echo Current dir `pwd`
# echo Compressing $OUTPUT_PATH
convert $RAW_FILENAME -encoding jpg -resize 640x480 -quality 86 -strip $RAW_FILENAME.tmp
rm "./$RAW_FILENAME"
mv "./$RAW_FILENAME.tmp" "$RAW_FILENAME"
OLDSIZE=`ls -l "$PICS_HOME/$BASEDIR/$aFile" | gawk 'FS=" " { print $5 }'`
NEWSIZE=`ls -l "$RAW_FILENAME" | gawk 'FS=" " { print $5 }'`
echo Compressed $OUTPUT_PATH from $OLDSIZE to $NEWSIZE
else
echo "File is empty: $PICS_HOME/$BASEDIR/$aFile"
fi
else
OLDSIZE=`ls -l "$PICS_HOME/$BASEDIR/$aFile" | gawk 'FS=" " { print $5 }'`
NEWSIZE=`ls -l "$RAW_FILENAME" | gawk 'FS=" " { print $5 }'`
echo Already Compressed $OUTPUT_PATH from $OLDSIZE to $NEWSIZE
fi

The result of this compression is that my 2Gb cart is now only 10% full rather than 100% full, so in theory, should be good for another 90 years, we'll probably have HD photo frames by then so the topic may become moot!

I hope these scripts will be useful fodder to anyone needing to do a similar thing.

Friday, 19 December 2008

Getting a Canon MP620 working with Ubuntu 8.04 x86_64

Not quite as straight forward as it should be from Ubuntu land. Following on from this other blog...

First job is to get it on the wireless network, I had to use winxp and the bundled client to poke the right values in the printer for WEP config. Printing from XP was flawless, naturally.

For Ubuntu printing, we need to build cups-bjnp but with 8.04 there is a snag. Just doing:

apt-get install libcupsys2-dev

.. results in all dependencies bar 1 file, 'sidechannel.h', which can be extracted from upstream 1.3.8 (cups/sidechannel.h) and copied into /usr/include/cups.

Making cups-bjnp was straight forward 'make', followed by 'make install' which adds 'bjnp' as a printer back-end in cups.

In the Printer Configuration wizard, setting up the MP620 was just a case of selecting the Canon610 being the closest relative, and adding the IP address of the printer.

The next stumble was finding test pages would be processed by the printer but never printed. This was simply a useless default setting for media source, picking 'automatic paper source switching' fixed that, and prints come forth.

If printing doesn't start almost immediately, the paper source/sizes are probably incorrect, check print options in the application used to print.

Close but no cigar, so far. I can print to the MP620 but test pages come out 'split' with almost 1 for 1 white lines horizontally, cutting off an A4 print at just after the Magenta text. Plain text prints suffer the same issues. Gah, its like looking at an ancient green screen Commodore PET! Its not the printer, can print XP test pages fine, can copy XP test pages fine. CUPS and/or printer settings not quiet right. Will post more details when I figure it out.

Thursday, 16 October 2008

Am I an Atlassian Lassie?

WTF? Once upon a time I wrote applications, I wrote web-apps, I created databases. Times change. I seem to be spending much time in the Atlassian eco-sphere, slowly sinking deeper and deeper into the API's but do I have the time!

The recent Jira 3.13 upgrade bust my previously unpublished email interoperability fixes to plug the gap between Jira inbound email support for issue creation and my companies nefarious Exchange server and user email configurations. Why care? Well, Confluence has no 'nice' way to interface Jira, its either one webapp or another. Confluence has nice macros like {jiraissues} and {jiraportlet} which rock (ok, we forgive almost current IE6 CSS problems in the macro), there is just no nice 'form' to create issues. It is however possible to email issues into Jira. But.

The problem is that we have multiple email formats, some of which are 'aliases' and not the 'one' that is in the mail attribute. Oh, and depending on which email client you use, it can change from that too. So basically, the Jira function was useless unless I could fix this. Rather than just patch my code and move on, this time, I decided to do it a little more 'properly' and create a framework that fixed all my problems, allowed extensions for other formats of inbound mail and kept such tweakery separate from the issue creation code. This got published Extendable Mail Handler. Currently, it only has an implementation that makes it compatible with Form Mail Ng, if only that worked with the current 2.[8,9] releases, 2.10m3 seemed to work fine, so fingers crossed. Here is a FormMail Ng example form for interest.

As the EMH integrates with LDAP, I've been continuing to work on and around the LDAP Util library, making great use of the Beanshell plugin to embed a few SQL queries and LDAP lookups, combining with the fabulous Run macro to do parameter replacement. The result is a fully interactive series of pages allowing users to easily search for an LDAP user, Confluence group, Jira group. I need to add a few screen-shots to do it justice. As I've almost entirely delegated Confluence Space management to users (thanks to CSUM) this last piece gives them the solution that thorny question 'who is in group X' how do I give access to user Y. Keeping the solution in the Confluence bubble should help.

A while back I tried to import a Twiki site from another area of the company using the Universal Wiki Translator for Twiki. As with most online translators, YMMV. In this case I managed to hit a a bug preventing upload from the off (seems to be a talent of mine), some pages got uploaded seamlessly, others were complete dross, all told 3500 pages got loaded, only later did I discern that some data was cruft and broke the XML export (I think). Man that was a couple of days of delete from ... INNER JOIN ... WHERE hell. I think I finally got down to the last 7 rows of data but got bored, well, scared, I think I finally had to remove foreign key constraints in order to remove circular referencing data. I'm not quite brave enough to try that live :) Anyway, back to the point. So we have a twiki system, its works well for those guys, and I have to say, it has one killer feature that Confluence is still scratching around for, forms. So simple, so elegant, so killer-feature. If you don't know about this, imagine a form on a Page, set some values through radio buttons, select drop-downs with images etc, hit 'save', the data gets saved, fine, but in a database from which tabular data can be extracted at a higher level. OK so, there is Scaffolding and Meta data2. Its getting there, just lacking maturity if compared to Twiki. Soooo:

Integrating Twiki data with Confluence? Hmmm, {html-include} would appear a useful ally but there's a problem, Twiki, like other sites uses relative URL's extensively, and guess what happens when you import from twiki.server.net to confluence.server.net? all the twiki links point to non-existent URLS on the confluence server. The solution seemed straight forward, and thanks to readily available source code I wrote my first non-library Confluence plugin, taking just a few hours to rewrite the URLs of relative links. Its not posted anywhere yet in its own right, but it got posted under CONF-13365. As ever with such things, it works out much better if someone else is always maintaining the code!

Continuing the LDAP theme. Having had my appetite whetted by how easy my first macro was, I fancy something UI'ish, and am mid hack converting the 'livesearch' macro into a 'liveldapsearch' macro. The original authors have done all the hard work, theoretically its just a slice and integration dice with the LDAP Util library and voila, useful dynamic ldap lookup (hrm, with no Beanshell).

Oh and then there is the ongoing grief associated with having to setup per-space inbound email account details. That sucks. Having written tooling (using The Confluence SOAP library to automate most of this) there is little payback to 'fix' this, however, the Confluence Mail Utilities Plugin fixes this in a neat way by essentially writing the bit of code that Confluence should have already to pull in all mail and deal with it once rather than have one config per Space. For info, my mail server is polled Continualy thanks to 60+ space email configs. A single poll is actually all thats required if you are smart about it. As usual that Confluence Mail Utilities Plugin wont work for me, so once again Im picking up a scalpel for some LDAP surgery.

And again speaking of LDAP, For a good while now I've been irked at the non-availability of the enterprise feature that is LDAP server failover. Goddammitalltohell, single points of failure should be avoided. In my org, stuff gets turned off. 'ping ping ping' goes my inbox. truly, how hard is it to add such a feature? I don't half feel stupid explaining that the Enterprise system we use can be configured for multiple LDAP repositories but isn't bright enough to identify them as failovers and people have to deal with seeing multiple instances of each other in the People Browser? Gah. One small vote for an issue, one even smaller step for an implemented feature!

That said, I love the products, its the overhead that gets you, we seem to now have all but 2 of them, any month now I'm gonna shout H O U S E !.

And finally to the title, with all this stuff going on, I seem to be spending all day every day doing this stuff, making me officially, my companies Atlassian Lassie :)

Tuesday, 26 August 2008

Another day in the life of a Confluence administrator

More builds
Those guys at Atlassian sure crank out the builds. Half of me is impressed that new fixes come in bite sized chunks, but the down side is having to manage that change, repeatedly. Take Confluence for example, our corporate system has oh 60 or so third party plugins giving it that extra whiz-bang, but every release I have to go through a time consuming verification process for each. What would be great in the future-vapourware tense is a way to script or otherwise define behaviour, almost like runtime JUnit tests.

Anyway back to the update cycle. Being a little behind the curve is a useful thing, sure as god made little green apples there will be bugs. Being behind lets other people fix find them first, sometimes I feel like a rampant RC tester, not just limited to Atlassian, but I seem to be gifted to find those ridiculously obscure bugs/problems that no-one else does, like X windows mouse acceleration being bust and having to do a manual xset, but I digress.

Upgrade/degrade
With the ever increasing visibility of Confluence in our company yours truly wants it all running nicely with as little foobar as possible. The use of 3rd party libs is both a benefit and a curse. With 2.8x and the new hover-menus I found that the MailformNG email integration I'd just spent a week or so fixing to get issues into Jira via a nice Form (and fixing Jira email handler to deal with multiple aliases for the same 'id'). Classic scenario, do I upgrade and void the work or upgrade to gain platform whiz-bang. In this scenario I went for the update/degrade, and am patiently sitting on the side waiting for a fix to FMNG-44. I suppose this could be my queue to get the source and figure out what needs to be done. Gah, another project, more email :/

MailformNG 'client' for Jira issue entry
Speaking of the Jira mail handler, I hear that Jira 3.13 is coming along nicely. I should probably create another project for this particular beast, which is a modified create or comment handler. The driver for me is that depending on where a user is and what email client they use, their email address may be different that their registered email address in ldap. Jira currently insists on a direct match, I needed an 'indirect match' which I posted under JRA-14973 including an implementation for our Active Directory server. I did hear that Jira4 may have improved email management, but I have no clue as to whether or not this will be API breaking. To create another project, more email :/

NTLM and LDAPutil
I'm still chugging away on the Confluence NTLM, recent fixes included extending the LDAP library code to parse multiple nodes in either atlassian-user.xml or osuser.xml, doing this enables the NTLM hash 'token' that a client offers to a Confluence instance with the NTLM authenticator to be passed around to all the configured Domain Controllers to see if its valid. For a single domain this seems to work well, and should work for multiple domains, but perhaps not. I don't know if there is some weird stuff going on when mulitple DC's are defined with duplicate content, time will tell. The current approach isn't terribly scalable, as each server config is tested in turn (my only get out for this approach is that if it actually works properly I can go and fix it, honest, one day.

LDAP filters
I have great fun with LDAP filters, as Im limited to working with Active Directory I've had enough time to come up with some funky filters. Whilst going into the NTLM side of things and figuring out I didn't have enough Domain Controllers defined I wanted to get a list of Domain Controllers.... Where to find... it dawned on me that I could create an LDAP filter to list the 'machine' entries in AD itself. It all revolves around the UAC (User Access Control) value, which has a bitwise representation for various magic properties including SERVER_TRUST_ACCOUNT and TRUSTED_FOR_DELEGATION. Using a filter: (userAccountControl:1.2.840.113556.1.4.803:=532480) its possible to list the underlying machines, and to categorically list all DC's that are in a replicated cluster.

Jira wishlist
I've just come back from another branch office after doing a tripple demo of Jira,Confluence and Bamboo. One of the main features asked for from Jira was the ability to create Sub-Projects in a Project. Some things are just hard to do.

Twiki -> Confluence ?
One of our offices has a Twiki instance, consisting of some 3600 pages. I started looking at the Universal Wiki Converter but ran into an annoying infinite loop bug but actually chewed through all pages. My mileage, as the saying goes, varied. Twiki has an awsome feature that as yet Confluence cannot match. Forms. Twiki forms allow live form value modification, typed fields etc, but the power comes from being able to refer to those values and to perform queries over those values. Today you can accomplish bits of this with MetaData but for typed values the only thing that comes in close is Scaffolding. Documentation is scant on scaffolding, and there are bugs (yet another victim of aggressive product releases I think).

Where does the time go
Its funny, in today's climate of that administrative utility device, the timesheet, its sometimes difficult to chalk up a few days to investigate really promising work like the plugins or just go fix the mailformNg plugin for 2.8.x, If only there were jobs doing good Samaritan open source development :) But then again, many projects, much email :/

Did I say I get too much email?
Its funny, after a couple of years of using Linux as a development environment by default (finally kicking the dualboot must-have-word habit) the only thing that keeps me meddling with 'Doze is email. In theory yes, Evolution, in practice, no. damn thing keeps dying on me. I was using VMwareServerfor a while but had a nasty experience when lo, my beta version expireth. Greaaaat. Would the new beta beta+1 build on my machine, would it heck. Feet.getInstance().march(); I saw OpenBox and finally plucked up the courage to commit time to setting it up. It works a treat and as an added bonus and at the click of CTRL-L (I think) I get native window integration (I forgive the authors for the occasional 'Doze background blit bleedthrough). Outlook running native-ish. Until that is, the Evolution connector manages to really get hooked up with Exchange.

I must go, there is a life out there just waiting for me to find it.

Tuesday, 14 August 2007

Well, it happened

Its shameful to admit, but this is my cherry blog. It happened almost by accident, but now its done. Ahh, the fredom to rant and rage to the world or not....

The geek in my is enjoying figuring out the ins and out of creating plugins for Confluence (second cherry of the day), not bad, not bad. It all looks reminiscent of Apache Struts and forwards to JSP , albeit with Velocity templates taking over from JSP, not surprising considering its a webapp.

Why do this? well, all I want to do is not spam a thousand people when I have to patch a server, playing nice I would like to issue targeted mail. How to do that? Given Confluence, its not straight forward but can be done, probably. I'm looking at modding the existing UserList plugin to spit out a CSV list of users, which can then be embedded in the Mail NG plugin. Giving me a nice form to hit the exact userbase, perfect. All I have to do is figure out how to deploy it.

Confluence plugins look pretty powerful, I have some ideas about graphing org charts, perhaps with Graphviz, but that doesn't look flashy enough. I just wondered about SVG and would you believe it, there's a plugin for SVG also, fab. Its just a shame Microsoft can't support open standards, SVG plugins for IE are very hard to come by, I eventually used the discontinued COREL plugin due to its support for interactive functionality. Just as well there's Firefox.