Ephesoft Web Service + RSS + Growl

After my first blog explaining how to get notification on your Android device if some batch instances are pending, I decided to create a simpler way to be informed. Because I'm a Mac user, I wanted to use Growl and creating notifications each time that a batch instance is pending for review or validation.

RSS Web Service

The first thing to create is the Ephesoft web service to generate a RSS feed. Following the same procedure as I explained in my first blog post. So let's create a simple POJO:

package com.bataon.ephesoft.rest.bean;

import java.util.Date;
import com.ephesoft.dcma.da.domain.BatchInstance;

public class RssBatchStatus {
	 
	String title;
	String summary;
	Date createdDate;
	
	public RssBatchStatus(BatchInstance batchInstance) {
		title = batchInstance.getIdentifier();
		summary = batchInstance.getStatus().toString();
		createdDate = batchInstance.getLastModified();
	}
	
}

Next, we need to create the controller in charge of this RSS Web Service:

package com.bataon.ephesoft.rest.controller;

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.bataon.ephesoft.rest.bean.RssBatchStatus;
import com.ephesoft.dcma.core.common.BatchInstanceStatus;
import com.ephesoft.dcma.da.domain.BatchInstance;
import com.ephesoft.dcma.da.service.BatchInstanceService;

@Controller
public class RssController {
	
	@Autowired
	private BatchInstanceService batchInstanceService;
 
	@RequestMapping(value="/rssfeed", method = RequestMethod.GET)
	public ModelAndView getFeedInRss() {
		List<RssBatchStatus> items = new ArrayList<RssBatchStatus>();
 
		List<BatchInstanceStatus> statusList = new ArrayList<BatchInstanceStatus>();
		statusList.add(BatchInstanceStatus.READY_FOR_REVIEW);
		statusList.add(BatchInstanceStatus.READY_FOR_VALIDATION);

		List<BatchInstance> batchInstances = batchInstanceService.getBatchInstanceByStatusList(statusList);
		for (BatchInstance batchInstance : batchInstances) {
			RssBatchStatus status  = new RssBatchStatus(batchInstance);
			items.add(status);
		}
 
		ModelAndView mav = new ModelAndView();
		mav.setViewName("rssViewer");
		mav.addObject("feedContent", items);
 
		return mav;
	}
 
}

And finally, we have to create the custom RSS view. This web service uses the library ROME. It is a set of RSS and Atom Utilities for Java that is open source under the Apache 2.0 license. So if you deploy this webservice, don't forget to deploy the ROME library in your folder ./Application/WEB-INF/lib.

package com.bataon.ephesoft.rest.rss;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
import com.bataon.ephesoft.rest.bean.RssBatchStatus;
import com.sun.syndication.feed.rss.Channel;
import com.sun.syndication.feed.rss.Description;
import com.sun.syndication.feed.rss.Item;

public class CustomRssViewer extends AbstractRssFeedView {

	@Override
	protected void buildFeedMetadata(Map<String, Object> model, Channel feed, HttpServletRequest request) {
		feed.setTitle("Ephesoft RSS feed");
		feed.setDescription("Ephesoft RSS feed");
		feed.setLink("http://");

		super.buildFeedMetadata(model, feed, request);
	}

	@Override
	protected List<Item> buildFeedItems(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		@SuppressWarnings("unchecked")
		List<RssBatchStatus> listContent = (List<RssBatchStatus>) model.get("feedContent");
		List<Item> items = new ArrayList<Item>(listContent.size());

		for (RssBatchStatus tempContent : listContent) {

			Item item = new Item();
			Description description = new Description();
			description.setValue(tempContent.getSummary());
			item.setTitle(tempContent.getTitle());
			item.setDescription(description);
			item.setPubDate(tempContent.getCreatedDate());

			items.add(item);
		}

		return items;
	}
}

And, here is a sample of RSS feed that this web service generates:

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Ephesoft RSS feed</title>
    <link>http://</link>
    <description>Ephesoft RSS feed</description>
    <item>
      <title>BI12</title>
      <description>READY_FOR_VALIDATION</description>
      <pubDate>Wed, 29 Jan 2014 19:26:16 GMT</pubDate>
    </item>
    <item>
      <title>BI13</title>
      <description>READY_FOR_VALIDATION</description>
      <pubDate>Wed, 29 Jan 2014 19:26:21 GMT</pubDate>
    </item>
    <item>
      <title>BI14</title>
      <description>READY_FOR_VALIDATION</description>
      <pubDate>Wed, 29 Jan 2014 19:26:16 GMT</pubDate>
    </item>
    <item>
      <title>BI15</title>
      <description>READY_FOR_VALIDATION</description>
      <pubDate>Wed, 29 Jan 2014 19:39:25 GMT</pubDate>
    </item>
  </channel>
</rss>

RSS

The next thing is to be able to get this RSS feed from my laptop. The previous created web service needs authentication... It allows to display only relevant notification for the user. In our case, we are just using the user ephesoft. To get the RSS feed, we just use the command curl like that:

curl -u ephesoft:demo http://192.168.169.196:8080/dcma/rest/rssfeed > ~/.feed/ephesoft.rss

Growl

Obviously, you need to install Growl on your Mac and as well growlnotify. Inspired from this blog, we create this PHP file in charge of reading a RSS feed and creates Growl notifications.

#!/usr/bin/php
<?php

// No trailing slash, the user that runs the script must be able to write here.
define( 'CACHE_DIR', '/Users/benjamin.chevallerea/.feed' );
define( 'ICON_IMAGE_PATH', '/Users/benjamin.chevallerea/.feed/twitter.png' );

// Supply the URL (quoted if it contains any querystring/weird chars) as the first parameter.
if ( empty( $argv[1] ) ) {
	echo "Usage " . $argv[0] . " URL_TO_CHECK [ICON_PATH]\n";
	exit;
}
$feed = simplexml_load_file( trim( $argv[1] ) );
if ( ! $feed ) {
	exit;
}

if ( count( $feed->channel->item ) ) {
	// Where this URL's content would be cached
	$cache_file = CACHE_DIR . '/' . md5( $argv[1] ) . '.cache';

	for ($i = 0; $i < count( $feed->channel->item ); $i++) {
		// RSS feed
		$post = $feed->channel->item[$i];
		$title = $post->title;
		$body  = $post->description;

		$cachedata = @file_get_contents($cache_file);
		if ($cachedata == null || strpos($cachedata,$title . "|" . $body . "\n") === false ) {
			// No cache hit, so overwrite the cache with new content
			$fh = @fope( $cache_file, 'ab' );
			if ( $fh ) {
				fwrit( $fh, $title . "|" . $body . "\n");
				fclos( $fh );
			}
			
			// Clean up strings for Growl
			$title = escapeshellarg( trim( strip_tags( html_entity_decode( $title ) ) ) );
			$body  = escapeshellarg( trim( substr( preg_replace('/\s+/is', ' ', strip_tags( html_entity_decode( $body ) ) ), 0, 300 ) ) );
			$icon = '--image ' . escapeshellarg( ICON_IMAGE_PATH );

			// Trigger notification
			`/usr/local/bin/growlnotify -n "FeedGrowler" -s $icon -t $title -m $body`;
		}
	}	
}
?>

CRON

Finally, we need to automate all of these elements. So we create a simple bash file in charge of downloading the RSS feed and calling the PHP file feedgrowler.php. This bash script will be called regularly using CRON.

# Update RSS feed
curl -u ephesoft:demo http://192.168.169.196:8080/dcma/rest/rssfeed > ~/.feed/ephesoft.rss

# Display notifications
~/.feed/feedgrowler.php ~/.feed/ephesoft.rss

Conclusion

So, very quickly, you can get Growl notifications connected to your Ephesoft instance. It allows to gain in productivity. You don't need anymore to open the web interface and to refresh to know if a batch instance is pending. And, because this web service needs user authentication, the generated RSS feed depends of the user and will display only relevant batch instances.

Comments

This is so cool.
Thank you...

I like to create fun things, let me know if you have any ideas !

Add new comment