Wednesday, June 19, 2013

Maven / Ant Alerts in OS X

The Case of the Forgotten Builds (Mac Edition)

You can see my previous post on Maven / Ant Alerts in Ubuntu for the Linux version

There are a few projects I work with that have long builds. I have a bad habit of alt-tabbing away from the build and promptly forgetting that I even started it only to come back 15 minutes later and not remembering if/when/why I built the project. What I need is a way for these tools to get my attention when they are done.

growlnotify To the Rescue!

Growl, a popular notifications app for OS X has a nice command line utility called growlnotify. Download an install it from that link and then with a short bash function and a few aliases we can have nice notifications for any command line we want!

The OS X Terminal as of 10.7 also responds to the "bel" escape character if it is in the background. For each bel that occurs while the Terminal is in the background a numeric badge appears and the counter it shows increments. The Terminal app icon also bounces a few times.

The combination of Growl and the Terminal bel provide a nice notification system that your command is done.

1. Install Growl and growlnotify

2. Edit ~/.bash_aliases:

cmdstatus()
{
    CMD=$1
    shift
 
    $CMD $@
    RETCODE=$?
    BUILD_DIR=${PWD##*/}
    BUILD_CMD=`basename $CMD`
    if [ $RETCODE -eq 0 ]
    then
        printf '\a'
        growlnotify -s -d $BUILD_CMD -n $BUILD_CMD -m "$BUILD_DIR: $BUILD_CMD successful
$(date)"
    else
        printf '\a\a'
        growlnotify -s -d $BUILD_CMD -n $BUILD_CMD -m "$BUILD_DIR: $BUILD_CMD failed
$(date)"
    fi
    return $RETCODE
}
alias ant="cmdstatus ant"
alias mvn="cmdstatus mvn"

3. Restart Your Terminal

Now you get nice success/failure messages out of your ant and mvn commands. The original commands return code is correctly preserved and this cmdstatus wrapper can be easily added to any other command you want via a simple alias line.





Monday, June 17, 2013

Maven / Ant Alerts in Ubuntu

The Case of the Forgotten Builds

There are a few projects I work with that have long builds. I have a bad habit of alt-tabbing away from the build and promptly forgetting that I even started it only to come back 15 minutes later and not remembering if/when/why I built the project. What I need is a way for these tools to get my attention when they are done.

libnotify To the Rescue!

So Ubuntu and its variants have a built in notification system that we can build on. By installing the libnotify-bin package we can use this system from the command line. With a short bash function and a few aliases we can have nice notifications for any command line we want!


1. Install libnotify-bin:

sudo apt-get install libnotify-bin

2. Edit ~/.bash_aliases:

cmdstatus()
{
    CMD=$1
    shift

    $CMD $@
    RETCODE=$?
    BUILD_DIR=${PWD##*/}
    BUILD_CMD=`basename $CMD`
    if [ $RETCODE -eq 0 ]
    then
        notify-send -c $BUILD_CMD -i emblem-default -t 3600000 "$BUILD_DIR: $BUILD_CMD successful" "$(date)"
    else
        notify-send -c $BUILD_CMD -i emblem-important -t 3600000 "$BUILD_DIR: $BUILD_CMD failed" "$(date)"
    fi
    return $RETCODE
}
alias ant="cmdstatus ant"
alias mvn="cmdstatus mvn"

3. Restart Your Terminal

Now you get nice success/failure messages out of your ant and mvn commands. The original commands return code is correctly preserved and this cmdstatus wrapper can be easily added to any other command you want via a simple alias line.


Tuesday, May 28, 2013

Call-It-Once JavaScript Function Wrapper

Just a quick utility function that makes it easy to wrap another JS function to ensure it is only called once:


var callOnceWrapper = function(f) {
    var called = false;
    return function() {
        if (!called) {
            f();
        }
        called = true;
    };
};


Use it by wrapping your callback that you only want to execute once:
var navigateCallback = callOnceWrapper(function() {
    document.location = event.location;
});
ga('send', {
  'hitType': 'event',
  'eventCategory': 'Flyout Link',
  'eventAction': 'UrlMinusDomainAndServletContext',
  'eventLabel': 'Portlet Name',
  'hitCallback': function() {
      navigateCallback
  }
});            
//Fallback in case hitCallback takes too long to get called, don't want clicks to hang
setTimeout(navigateCallback, 100);

Even though there is potential for navigateCallback to get called twice the wrapper only allows the first invocation through.

Wednesday, May 22, 2013

Fixing ICS Time Zone

I was getting my agenda setup for the upcoming 2013 Apereo conference in San Diego and was excited to see their scheduling app let you select presentations and export a .ics file. Yay, something easy to import into Google Calendar and I'll have my whole schedule right on my phone!

Well, that was the case until I imported the events and had no attached time-zone information ... boo!

So here is the quick-and-dirty hack to add time-zone information to your .ics file.

Add a VTIMEZONE Block

These go right above the first BEGIN:VEVENT block in your ics file. You only need to add time-zone definitions for the time zones you want to reference in your events. At the bottom of the post are more timezone blocks
BEGIN:VTIMEZONE
TZID:America/Los_Angeles
X-LIC-LOCATION:America/Los_Angeles
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
TZNAME:PDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
TZNAME:PST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE

Update DTSTART and DTEND

For each VEVENT you want to set a timezone for update the DTSTART and DTEND to include a timezone reference.
Before:
DTSTART:20130602T130000
DTEND:20130602T160000
After:
DTSTART;TZID=America/Los_Angeles:20130602T130000
DTEND;TZID=America/Los_Angeles:20130602T160000

US VTIMEZONE List

Below are VTIMEZONE blocks for: Pacific, Mountain, Mountain - Arizona, Central, and Eastern time zones.

BEGIN:VTIMEZONE
TZID:America/Los_Angeles
X-LIC-LOCATION:America/Los_Angeles
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
TZNAME:PDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
TZNAME:PST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VTIMEZONE
TZID:America/Phoenix
X-LIC-LOCATION:America/Phoenix
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0700
TZNAME:MST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
BEGIN:VTIMEZONE
TZID:America/Chicago
X-LIC-LOCATION:America/Chicago
BEGIN:DAYLIGHT
TZOFFSETFROM:-0600
TZOFFSETTO:-0500
TZNAME:CDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0500
TZOFFSETTO:-0600
TZNAME:CST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VTIMEZONE
TZID:America/New_York
X-LIC-LOCATION:America/New_York
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE

Tuesday, May 14, 2013

Jenkins Build Latest Git Tag

We have a Jenkins job that we want to automatically build the latest tag in a git repository. Turns out this is quite doable right out of the box!

Step One:
Use tags with a slash '/'. This helps you target builds for just one set of tags. ex: muyw/4.0.11.11

Step Two:
Specify a Refspec in the Jenkin's git plugin that only selects these tags: +refs/tags/myuw/*:refs/remotes/uw/tags/myuw/*

Step Three:
Specify a Branch Specifier to build these tags: */tags/myuw/*




Monday, April 26, 2010

Pre-compile JSPs from a Maven Overlay

Maven WAR Overlays are wonderful things, allowing for manipulation of a WAR artifact published by someone else into what you need for your application.

Pre-compiling JSPs (JSPC) is great when you don't want users to potentially be hit with the wait for your container to compile the JSP on first visit.

Here is how to put the two together:

    
    
        org.jasig.portlet
        WeatherPortlet
        ${WeatherPortlet.version}
        war
    
    
    
        javax.portlet
        portlet-api
        provided
    
    
        org.apache.pluto
        pluto-taglib
        provided
    


    
        
            org.apache.maven.plugins
            maven-war-plugin
            2.0.2
            
            
                
                    build-directory-tree
                    process-resources
                    
                        exploded
                    
                    
                        
                            
                                org.jasig.portlet
                                WeatherPortlet
                                
                                    **
                                    META-INF/context.xml
                                
                            
                        
                    
                
                
                    build-war
                    package
                    
                        war
                    
                    
                        ${project.basedir}/target/jspweb.xml
                    
                
            
        
        
            org.codehaus.mojo.jspc
            jspc-maven-plugin
            2.0-alpha-3
            
                
                    
                        compile
                    
                
            
            
                ${project.basedir}/target/${project.artifactId}/WEB-INF/web.xml
                
                    ${project.basedir}/target/${project.artifactId}
                    
                        **/*.jsp
                    
                
            
            
                
                    org.codehaus.mojo.jspc
                    jspc-compiler-tomcat6
                    2.0-alpha-3
                
            
        
    



In the above example the following things are happening:
  1. The org.jasig.portlet:WeatherPortlet WAR artifact is declared as a dependency. This is the WAR that will have its JSPs compiled.
  2. Due to operation ordering the maven-war-plugin is split into two executions.
    1. First the build-directory-tree execution extracts the overlay WAR during Maven's process-resources phase. This ensures the WAR contents are in place before JSPC runs.
    2. Second the build-war execution re-packages the WAR using the JSPC generated XML file as the web.xml included in the WAR.
  3. The JSPC plugin is configured to look in the target directory for the web.xml to modify and the JSPs to compile.

Monday, July 14, 2008

Unit testing Spring-LDAP code with ApacheDS

The Spring LDAP framework is a great library to assist in working with LDAP servers through a more manageable API. It provides the niceties that the DataSource interface does for JDBC along with support similar to the Spring JDBC framework. One area that has been lacking though is testing. With JDBC based code it is easy enough to use HSQLDB to provide an in-memory database to test against. With LDAP based code there hasn't been a good solution, until the Apache Directory project came along.

Apache Directory is a 100% Java LDAP implementation and includes support for in-memory LDAP instances for unit testing. Using this support plus a few helper classes to bridge the gap to Spring LDAP providing unit tests for LDAP related code is easy.

First add the necessary dependencies. If you are using Maven your project needs to depend on the following for testing:


Second, add AbstractDirContextTest.java and SingleContextSource.java to your project.

Finally extend AbstractDirContextTest for your LDAP code test class.


Your test class needs to provide a partition name, which is the root of the DN for the server to test against, and a Resource array of ldiff files to load into the LDAP server. For the test above the ldiff file looke like: