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,.