I was rather glad to see a question come up on the the Salesforce StackExchange about how to load data from RSS into custom objects, as it was one of the few times that I could offer a complete solution without setting aside a couple hours to test out some new code (not that I mind doing that, any good excuse to write some Apex for a few hours…).  As it happens, I was already doing this internally to help our team of crack evangelists track blog posts.

When I first picked up this task, I did what many a developer would probably do in that situation – I opened a Google Spreadsheet and starting entering in new posts by hand.  This meant manually checking the blogs every morning, cutting and pasting a lot of data into the spreadsheet and often reformatting the text as well (why modern applications insist on trying to maintain the HTML of everything you copy is beyond me).  I would often hold off on this chore but a couple times a week and by that time it would take even longer and the data would be even more out of date.

It was a solution that solved virtually nothing.  Yes, I was recording blog data into a spreadsheet somewhere in Google Docs.  But the main goal was to give people on staff something of a dialtone of blogging behavior – and that wasn’t really happening.  It was a classic case of the Cobbler’s Paradox, by spending all my time talking about shoes to others I was myself going barefoot.  Apex was the elegant tool I was forgetting to use.

Firstly, I wanted something which would run automatically.  So I used the schedulable interface so that the class could be run in the background at given intervals:

global class RSSHandler implements Schedulable {

    global RSSHandler() {

    }

    global void execute(SchedulableContext c) {
        updateDeveloperBlog();
    }

Next I needed a callout so that we can grab the RSS feed (in this case, the feedburner feed of the developer.force.com Developer Relations blog).  Using the XML classes and a Custom Object list, I’m ready to compare the current RSS with the currently known blog posts:

@future(callout=true)
    static global void updateDeveloperBlog() {
        List<Dom.XMLNode> recentPosts = RSSHandler.getRSSFeed('http://feeds.feedburner.com/developerforce/developerelations?format=xml');
        List<Blog_Entry__c> blogEntries = new List<Blog_Entry__c>();
        List<String> titles = new List<String>();
        List<Blog_Entry__c> entriesToAdd = new List<Blog_Entry__c>();

        String listOfBlogs = '';

        System.Debug('# OF POSTS FOUND:' +recentPosts.size());

I then do a SOQL call to grab the current blog posts and eliminate any of the ones from the RSS feed we already have the title for:

for(Blog_Entry__c bp : blogEntries) {
            titles.add(bp.Title__c);
        }

        List<Blog_Entry__c> blogs = [SELECT Id, WordPress__c, Title__c, Author__c from Blog_Entry__c WHERE Title__c IN :titles];
        for(Blog_Entry__c blogEntry : blogEntries) {
            Boolean added = false;
            for(Blog_Entry__c blog : blogs) {
                if(blog.Title__c == blogEntry.Title__c) { added = true; }
            }
            if(!added) { entriesToAdd.add(blogEntry);  }
        }

        insert entriesToAdd;

And set up some text for the email we want to send out:

if(entriesToAdd.size() > 0) {
            for(Blog_Entry__c blogEntry : entriesToAdd) {
                listOfBlogs += '<BR/><a href="'+blogEntry.Link__c+'"><strong>'+blogEntry.Title__c+'</strong></a>,&nbsp;'+blogEntry.Author__c+''+ + '<BR />';
                listofBlogs += '<a href="http://twitter.com/?status='+EncodingUtil.urlEncode(blogEntry.Title__c +', '+blogEntry.Link__c, 'UTF-8')+'">Tweet This</a><BR /><HR />';
            }
            RSSHandler.sendEmailNotice(listOfBlogs);
            }

The actual RSS processing is handled in a utility function.  Notice here that the function is looking for item nodes.  These are the actual posts, and what the class needs is a list of just those nodes to compare against a Custom Object.  If you wanted to use this process for another XML feed (say an authenticated data point) – this is where you would swap out for nodes fitting that particular XML message.

static global List<Dom.XMLNode> getRSSFeed(string URL) {
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        // url that returns the XML in the response body  

        req.setEndpoint(url);
        req.setMethod('GET');
        HttpResponse res = h.send(req);
        Dom.Document doc = res.getBodyDocument();

        Dom.XMLNode rss = doc.getRootElement();
        System.debug('@@' + rss.getName());

        List<Dom.XMLNode> rssList = new List<Dom.XMLNode>();
        for(Dom.XMLNode child : rss.getChildren()) {
           System.debug('@@@' + child.getName());
           for(Dom.XMLNode channel : child.getChildren()) {
               System.debug('@@@@' + channel.getName());

               if(channel.getName() == 'item') {
                    rssList.add(channel);
               }
           }
        }

        return rssList;

    }

Finally, send out an email:

    global static void sendEmailNotice(String links) {
	Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(Label.blogemaillist.split(','));
        mail.setSubject ('[BLOGLOG] New Entries');
        mail.setHTMLBody('<h3>New Blog Posts:</h3>'+links+'<br/><br/>');

        Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
	}

And bam – set up a scheduled Apex run two or three times a day, the Apex will automatically add the data into the system and alert a group of people.  Notice that email list is being managed by a Custom Label, which means the list can be updated even while the Apex is scheduled (because the code can’t be changed if there are any scheduled tasks).  Now what was a manual chore is an automatic process and the solution actually solves the problem.

You can see the entire class up on gist.

What do you use scheduled Apex for?  Let us know in the comments below, or catch me on twitter.

tagged , , , Bookmark the permalink. Trackbacks are closed, but you can post a comment.
  • http://www.facebook.com/mohitkumar.srivastav.1 Mohitkumar Srivastav

    Josh Perfect!!!This is really awesome stuff .Thanks for this .