The whole world's gone associative on me!

Supposed you have an indexed array in PHP…
$foo = array(‘apple’, ‘orange’, ‘banana’);
And you run…
foreach ($foo as $index => $bar) {
if ($index == 1) unset($foo[$index]);
}
then the resulting array will have these indexes!:
0, 2
If you then try to iterate the array in the standard fashion:
for($i = 0; $i < count($foo); $i++) {
}
you’ll get an error when $i is 1.
The fix for resetting indexes if you ever unset in a loop is to call:
$foo = array_values($foo);
after the loop!
Lesson: EVERY array in PHP is an associative array, even “indexed” arrays.

Badass JavaScript: CoffeePhysics: A Fast New Physics Engine Written in CoffeeScript

Badass JavaScript: CoffeePhysics: A Fast New Physics Engine Written in CoffeeScript

Good presentation by SpringSource around the rise of AMQP & RabbitMQ as messaging solutions


RabbitMQ + Spring = Easy Integration

If you’ve never heard of RabbitMQ, it is a robust messaging system (written in Erlang) based on the AMQP standard, which is a wire-level protocol designed to be cross platform and language agnostic. We utilize RabbitMQ here at Traackr in our back-end technology stack, where we offload work that is not required for immediate consumption by our system. Not only have we found RabbitMQ to be incredibly fast and durable, but it also offers a slick UI and administrative controls for examining the state of your message queues and server.

We chose to integrate with RabbitMQ using the Spring AMQP project (http://www.springsource.org/spring-amqp). The Spring AMQP project provides all the necessary classes for setting up RabbitMQ transaction managers, connection factories, message templates, listeners, etc. As always, Spring provides terrific documentation and getting your application to successfully send and receive messages is a piece of cake - http://static.springsource.org/spring-amqp-net/docs/1.0.x/reference/html/amqp.html

Now, regarding message consumers, Spring recommends creating your listener containers with a bean definition (via XML) so that it can simply run in the background:

<object name="MessageListenerContainer" type="Spring.Messaging.Amqp.Rabbit.Listener.SimpleMessageListenerContainer, Spring.Messaging.Amqp.Rabbit">
    <property name="ConnectionFactory" ref="RabbitConnectionFactory"/>
    <property name="Queue" value="some.queue"/>
    <property name="MessageListener" ref="SomeListener"/> </object>

However, we did things a little bit differently here at Traackr, and here is why you should too. We create and manage our own listener containers via our own Service, which resembles something like:

@Service
public class MyRabbitMQListenerService
{
    ...
    private Map<String, SimpleMessageListenerContainer> messageListenerContainers = new HashMap...
    ...
    @Override
    public void afterPropertiesSet() { // spring bean initializer
        // pseudo-code
        for (String queue : my_list_of queues) {
            SimpleMessageListenerContainer container = SimpleMessageListenerContainer();
            container.queue = queue;
        container.MessageListener = new listener_delegate;
           ... set other stuff
           messageListenerContainers.put(queue, container);

             // Start by default (or not if you're no fun)
            container.start();
        }
    }
   
    public SimpleMessageListenerContainer getListenerContainerForQueue(String queue) {
        return this.messageListenerContainers.get(queue);
    }
}

This allows us to quickly access the SimpleMessageListenerContainer registered to each queue. One of the great things about the SimpleMessageListenerContainer class is that it provides methods for starting and stopping message consumption…

Now, suppose we expose two REST-ful endpoints that look something like this:

@RequestMapping(value = "/startMessageContainer/{queue}", method = RequestMethod.GET)
@RequestMapping(value = "/stopMessageContainer/{queue}", method = RequestMethod.GET)

With some extra code to connect the dots, we can now pause and resume message consumption for any queue at will … Awesome stuff!

@RequestMapping(value = "/stopMessageContainer/{queue}", method = RequestMethod.GET)
@ResponseBody
String stopMessageContainer(@PathVariable("queue") String queue) {
   // Quick & dirty
   myRabbitMQListenerService.getListenerContainerForQueue(queue).stop();
   return "success";
}

What’s the advantage of this, you might ask? Well, suppose the responsibility of the message consumer is to take the message payload and send that information to a 3rd party service. So, what happens when that 3rd party service goes down? Well, most likely an exception will be raised by the message consumer, triggering a roll-back by the RabbitMQ transaction manager, and the message will get put back on the queue. Now if this 3rd party service is down for a day, this cycle of roll-backs would continue until the external service was back up (unfortunately, RabbitMQ has no notion of a dead letter queue). If we were aware of the problem, we could easily shut down consumption on this queue and prevent all the unnecessary network chatter.

Even better, what if the message consumer imposed thresholds for certain types of errors that when met would automatically stop themselves. Using the above approach of encapsulation, we can achieve that, and that is some VERY powerful stuff.


Grails external logging

Grails has some fantastic built-in facilities for logging. If you haven’t see them already, you should check them out.

There is only one problem: what happens if you want to configure your logging outside of Grails at the app server layer? Grails is only one of the apps in our stack, so we prefer to control our logging configuration at the app server JVM layer. Looking at the Grails user guide’s logging section, there is seemingly no clear way of doing this. But if you know one thing about Grails, you know that you can do anything with it. You just have to do some digging. After you do, you’ll find out that Grails is using an app context listener plugin to wrap and control logging in a WAR deployment: org.codehaus.groovy.grails.plugins.log4j.web.util.Log4jConfigListener . This is configured inside the web.xml that is deployed with the app, so you need to modify it before deployment. There are two ways to do this. You can run 

grails install-templates

and edit out the Log4j listener element from src/templates/war/web.xml:

<listener>
   <listener-class>org.codehaus.groovy.grails.plugins.log4j.web.util.Log4jConfigListener</listener-class>
</listener>

Alternatively, you can create a file scripts/_Events.groovy under your app with these contents:

// Add this code to scripts/_Events.groovy under your Grails app
// Removes Log4jConfigListener from Grails web.xml

import groovy.xml.DOMBuilder
import groovy.xml.XmlUtil
import groovy.xml.dom.DOMCategory

eventCreateWarStart = { warName, stagingDir ->

   def webXmlFile = new File(stagingDir, '/WEB-INF/web.xml') 
   def wxml = DOMBuilder.parse(new StringReader(webXmlFile.text)).documentElement

   String className = 'org.codehaus.groovy.grails.plugins.log4j.web.util.Log4jConfigListener'
   use (DOMCategory) {
      def listenerNodes = wxml.'listener'
      for (n in listenerNodes) {
         if (n.'listener-class'.text() == className) {
            wxml.removeChild n
         }
      }
   }

   webXmlFile.withWriter { it << XmlUtil.serialize(wxml) }
}

That’s it!


UTF-8 all the way

Recently we have been tracking the various integration points in the Traackr technology stack and making sure we are 100% UTF-8 compliant all the way thru. Each layer has it’s own set up and required configuration. Sometimes right out of the box, sometimes with more tweaking. 

Ran into this article while doing some research, that shows how to make your web app UTF-8 enabled. A lot of configuration for something seemingly simple.

http://www.itnewb.com/tutorial/UTF-8-Enabled-Apache-MySQL-PHP-Markup-and-JavaScript


Effective Scala

Effective Scala

Using Traackr API

Today Engage121 announced they are launching a new version of their product that integrates with Traackr: Engage121 Launches Version 2.1

How do they do that you might ask? Well, very easy, they are using our awesome API. I thought I would show you how you can do it to. We are going to build a little Traackr widget from one of our alpha lists, Cloud Computing. The widget will display random posts from the list on a web page.

First of, the HTML for the page. Let’s keep it simple. We load JQuery because we will need it later to load the A-List via the API and display the posts.

The body contains a simple DIV and TABLE where we will display the image for the influencer and the text of the post.

<!DOCTYPE html>
<html>
    <head>
        <title>AList Widget</title>
        <script type=“text/javascript”
            src=“https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js”>
        </script>
    </head>
    <body>
        <h1>A-List Widget</h1>
        
        <!– alist title –>
        <div id=“alist-title”><i>Loading</i></div>
        
        <!– random post to display –>
        <div id=“alist-post" style="display: none; margin-top: 15px;”>
            <table><tr>
                <td>
                    <!– author's image –>
                    <img id=“author" src=”“/>    
                </td>
                <td>
                    <!– post text –>
                    <div id="post”></div>
                </td>
            </tr></table>
        </div>
        
    </body>
</html>

Now, the fun part. The trick it load to load the A-List via our API, here is the link for it. If you are a Traackr customer, this link is accessible from your campaign’s setting.

Once we have loaded the A-List, we can simply call the Javascript function show_post() every 5 seconds to load a new post. We select each post by randomly selecting 1 influencer from the list, then randomly select 1 channel from this influencer and finally 1 random post. Here is what it looks like:

<script type=“text/javascript”>
            $(document).ready(function(){
                $.ajax({
                    url: 'http://alist.traackr.com/influencers/all/4233.json’,
                    data: {sec: '2728ea00020714632aa811e6f4a89e3a’},
                    dataType: 'jsonp’,
                    jsonp: 'jsonpcallback’,
                    success: function(data) { show_alist(data); }
                });
            });
            
            alist = null;

            var show_alist = function(data) {
                // read list and display title
                alist = data;
                $(’#alist-title’).html(alist.name);
                setTimeout(show_post, 5000);
            } // End function show_alist()
            
            var show_post = function() {
                // Find random influencer
                current_influencer = Math.floor(Math.random() * (alist.list.length - 1));
                influencer = alist.list[current_influencer];
                // Find random channel
                current_channel = Math.floor(Math.random() * (influencer.channels.length - 1));
                channel = influencer.channels[current_channel];
                // Find channel has posts
                if ( channel.posts.length > 0 ) {
                    // FInd random post
                    current_post = Math.floor(Math.random() * (channel.posts.length - 1));
                    // get data
                    img  = influencer.pics.small;
                    post = channel.posts[current_post].title;
                    url  = channel.posts[current_post].url;
                    // display
                    $(’#alist-post’).hide();
                    $(’#author’).attr(‘src’, img);
                    $(’#post’).html(’<a target=“_blank" href=”' + url + ’“>' + post + ’</a>’);
                    $(’#alist-post’).fadeIn(750);
                    setTimeout(show_post, 5000);
                }
                else {
                    setTimeout(show_post, 100);
                }
            }
        </script>

15 min in the oven at 350 and we are done. Check out the final result

And the best part about it? Traackr’s A-Lists refresh automatically weekly, so without having to do anything, just come back every week and discover new content.

That’s all folks!


Dependency hell

Spent quality time with @bbguitar77 upgrading to Grails 2.0.0. Of course this took us down the rabbit hole to dependencies hell. But we survived, we are back and all unit tests are now passing.

Onto the next challenge!