Flash 10.1 breaks multiwindow applications

June 22nd, 2010 by fredrik

Adobe has made their Flash Player version 10.1 available for some time now. Among some more or less nifty features, they also have a new way of preserving CPU and resources when an application is out of view (different tab or minimized), the application is throttled to a meager 2 frames per second instead of about 60 frames per second.

The throttling effects everything in the application, Timers, Events, LocalConnections etc. The behavior is explained very well in Tinic Uro’s blog post.

I think I understand the rationale here. Currently, an application is running full speed even when it is out of sight from the user. This means that flash applications running on background tabs might eat up CPU without any real reason for it. Since Flash has been taking a lot of flak for this lately I can see how they are eager on improving this. The general idea behind this is sound.

However, my problem with this (and other companies as well)  is that you are breaking backwards compatibility. The throttling affects all timers and event handling. Any type of Flash application that uses multiple windows might use LocalConnection to communicate between the windows/applications. After all, that’s what it’s there for. If any of the participating applications are minimized or hidden, they will almost stop producing/consuming since they are throttled down to 2 FPS.

What is even worse is that you get no notification when this occurs. There are no callbacks or events triggered. Suddenly your application might be running at a 30th of the default speed and you will not be told about this. There is currently no option to avoid being throttled either. To me this is not acceptable if I am developing RIA:s. Imagine writing a desktop application in C++ where your timers suddenly could jump down from 60 FPS to 2 FPS. Without a callback. How would that go with the developer community?

Can this be fixed?

I think so. If Adobe only adds an opt out option for an application I think it would be fine. The default behavior could still be the throttled solution, which would probably work in 90+% of the Flash applications out there. For the freaks like us that are relying on a stable timer and LocalConnection we could explicitly say that we want full FPS even when hidden.

The argument that this could be abused is moot in my opinion. This is the current behavior so you are not making something worse even if everyone decides to opt out from throttling. Besides, what would be the motives for people to ‘abuse’ this behavior? Some evil scheme to waste CPU cycles on people’s computers?

But until then?

If you application is running into problems because of the throttling, there are some things you can try to make things better.

1. Loop a silent MP3 in your applications. Yes, I am serious. This will ramp up the FPS from 2 to 8. Still not much, but four times faster.

2. For LocalConnections you can run a separate LocalConnections per client (if applicable). This will allow you to send more data per tick. *

3. Batch data over LocalConnections. Aggregate as much as you can between ticks and then send it as an Array. Pack it up on the other side.

Remember that when your ticks go down you need to try and perform as much work as possible for each tick. Of course, this is a bit against the design principles for an asynchronous framework, but hey, that’s what happens when you start to nerf the framerate.

* Edit: This does not seem to be possible. The routing seems to be executed outside the LocalConnection, meaning that all events sent will be dispatched sequentially in a throttled manner to all recipients. Ergo, if you have one broker and four clients (think online poker game with one lobby and four tables) then for the 2 FPS case each client will receive a maximum of 1 event every two seconds. Yikes.

Fredrik Johansson is a founder and CEO of Cubeia Ltd.

You can contact him at: fredrik.johansson(at)cubeia.com

Unit Tests with Guice and Warp Persist

April 25th, 2010 by larsan

Yesterday I needed to do some unit testing for a project using Guice and Warp Persist. And one thing that seems to be lacking, or wasn’t to be found be me yesterday, is the kind of unit testing you can do with Spring, where each method is wrapped by a transaction which is rolled back when the method ends.

To simplify, it enables you to do this:

@Test
public void createUser() {
    User u = userService.createUserWithId(1);
}

@Test
public void createUserWithSameId() {
    User u = userService.createUserWithId(1);
}

If you assume the “userService” is transactional, we’re on a database that spans multiple methods, and that the user ID must be unique, the above pseudo-code should fail as we’re trying to create two users with the same ID. If, however, there was a transaction wrapping both methods, and that transaction was rolled back, we’d be fine.

So, can you do it with Guice and Warp Persist? Sure you can!

(I’m using TestNG and JPA by the way, but you’ll get the point).

We’ll create a base class that sets up the Guice context as well as handles the transactions for us. Let’s start with creating the methods we need:

public abstract class JpaTestBase {

  @BeforeClass
  public void setUpJpa() throws Exception {
    // setup guice + jpa here here
  }

  @AfterClass
  public void tearDownJpa() throws Exception {
    // stop jpa here
  }

  /**
   * Return the module needed for the test.
   */
  protected abstract List<? extends Module> testModules();

  @BeforeMethod
  public void setupTransaction() throws Exception {
    // create "session in view"
  }

  @AfterMethod
  public void cleanTransaction() throws Exception {
    // rollback transaction and close session
  }
}

We’re using the TestNG “before” and “after” class to setup and tear down JPA. If the test was in a bigger suite you could probably do it around all test classes, but this will do for now. I’m also including a “testModules” method that subclasses should use to make sure their own test classes are setup correctly.

Before we go on, I’ll add some dependencies which will be explained later:

@Inject
protected PersistenceService service;

@Inject
protected WorkManager workManager;

@Inject
protected Provider<EntityManagerFactory> emfProvider;

We’ll setup the Guice context and the JPA persistence service in the “setUpJpa” method:

@BeforeClass
public void setUpJpa() throws Exception {
  // create list with subclass modules
  List<Module> list = new LinkedList<Module>(testModules());

  // add persistence module
  list.add(PersistenceService
            .usingJpa()
            .across(UnitOfWork.REQUEST)
            .forAll(Matchers.annotatedWith(Transactional.class), Matchers.any())
            .buildModule());

  // modules to array and create Guice
  Module[] arr = list.toArray(new Module[list.size()]);
  injector = Guice.createInjector(arr);

  // make sure we get our dependencies
  injector.injectMembers(this);

  // NB: we need to start the service (injected)
  service.start();
}

The persistence service will work across UnitOfWork.REQUEST as that’s what we’re emulating here. I’m also matching the transaction for any classes, this enables me to mark an entire class as transactional, as opposed to single methods, which I find handy.

All we need to do to shut down is to close the service, like so:

@AfterClass
public void tearDownJpa() throws Exception {
  service.shutdown();
}

Now, let’s wrap the methods. Remember our dependency injections earlier? Well, here’s where they come in handy. The WorkManager is used by Warp Persist to manage a session, we can tell it to start and end “work” and this will correspond to an EntityManager bound to the current thread. Let’s start with that:

@BeforeMethod
public void setupTransaction() throws Exception {
  workManager.beginWork();
}

@AfterMethod
public void cleanTransaction() throws Exception {
  workManager.endWork();
}

So before each method we’ll open a new EntityManager which will be closed when the method ends. So far so good. Now, in order to enable a rollback when the method ends we first need to wrap the entire execution in a transaction, which means we need to get hold of the EntityManager. Luckily, Warp Persist has a class called ManagedContext which holds currently bound objects (a bit like a custom scope), in which we’ll find our EntityManager keyed to it’s persistence context, ie. the EntityManagerFactory that created it. Take a look again at the injected dependencies we injected above: As the test only handles one persistence context we can safely let Guice inject a Provider for an EntityManagerFactory for us and assume it is going to be the right one.

Still with me? OK, let’s do it then:

@BeforeMethod
public void setupTransaction() throws Exception {
  // begin work
  workManager.beginWork();
  // get the entity manager, using it's factory
  EntityManagerFactory emf = emfProvider.get();
  EntityManager man = ManagedContext.getBind(EntityManager.class, emf);
  // begin transaction
  man.getTransaction().begin();
}

@AfterMethod
public void cleanTransaction() throws Exception {
  // get the entity manager, using its factory
  EntityManagerFactory emf = emfProvider.get();
  EntityManager man = ManagedContext.getBind(EntityManager.class, emf);
  // rollback transaction
  man.getTransaction().rollback();
  // end work
  workManager.endWork();
}

And that’s it! Each test method is now within a transaction that will be rolled back when the method ends. Now all you need to do is to write the actual tests…

Firebase Lobby and Bandwidth

April 1st, 2010 by fredrik

Upon popular demand I have made an analysis of the bandwidth requirements for running the Cubeia Poker on Firebase with the lobby. The scope was to test 8 000 simulated poker users on a 4-way cluster where every user is also subscribing to the entire lobby tree (i.e. all tables). The values of interest are external and internal bandwidth usages.

This somewhat technical document can be found here.

Asynchronous Games in Firebase; pt II

March 12th, 2010 by larsan

Last post I looked at the motivation for writing asynchronous multiplayer games on top of Firebase.  This post I’ll sketch an outline on how to actually do it.

The first thing to consider is that we now have two notions: The Firebase concept of area (called “table” for legacy reasons) and the overall concept of a “game”. Firebase tables are associated with games, but whereas in a synchronous game the table probably would be the game such that if the table is closed, the game is over, in asynchronous games the table may come and go, but the game itself would survive.

Oh by the way, I’ll use Java in this post, but remember you can write it in script languages Ruby, Python and Groovy as well. :-)

Let’s step it through:

  1. The game is created. This is probably done on a website somewhere and does not involve Firebase at all.
  2. Client connects. When game client is opened (someone wants to make a move), the client connects to Firebase and does the following:
    1. Search the lobby for any table with the correct “gameId” set in the attributes.
    2. If a table is found, attempt a “join” command.
    3. If a table is not found, or the join fails, send a table creation request and make sure to include the “gameId”.
  3. Activator creates table. When a client cannot find a table for the game, it send a table creation request, the activator then reads the game and its state from database, and creates a new table.
  4. Game play. The player makes its moves and actions normally via Firebase. The game in Firebase either saves the state on each action, or delegates to the time when the table is being closed (see below).
  5. Table closes. When the activator finds  table which has not been accessed for some time. If needed it should also save the game state at this point (see above).

I’ll focus on points no. 3, 4 and 5 above for the rest of this post. And I’ll use code examples from the Kalaha game I’m currently involved in writing.

Activator / Table creation
The game activator in Firebase is the components that know how to create and destroy tables in the system. We’ll follow best practises (but we’ll skip the “init” state for now) as it helps us save the state to database.

The activator should first make sure to implement RequestAwareActivator to make sure it gets the requests:

public class ActivatorImpl implements GameActivator,
   RequestAwareActivator {

[...]

When a client wants a table to join for a specific game, it’ll send a table creation request, and the activator should read the game state from the database and create a new table. Somewhat compressed, it may look like this:

@Override
public RequestCreationParticipant getParticipantForRequest(
        int pid, int seats, Attribute[] atts)
    throws CreationRequestDeniedException {

    // find the game id in the parameters
    int gameId = getKalahaGameId(atts);
    if(gameId == -1) {
        // you may want to handle this as a special form of "new game"
    } else {
        log.debug("Ressurecting game " + gameId + " for player id " + pid);
        // read the game from the database
        Game game = gameManager.getGame(gameId);
        if(game == null) {
            // code 1 for "no such game"
            throw new CreationRequestDeniedException(1);
        }
	return new Participant(game);
    }
}

The Participant is an inner class for handling the request, like so:

private static class Participant implements RequestCreationParticipant {

    private final Game game;

    public Participant(Game game) {
        this.game = game;
    }

    @Override
    public void tableCreated(Table table, LobbyTableAttributeAccessor atts) {
        table.getGameState().setState(new net.kalaha.game.action.State(game.getState()));
        atts.setStringAttribute(TABLE_STATE_ATTRIBUTE, "OPEN");
	atts.setIntAttribute("gameId", game.getId());
    }

    @Override
    public LobbyPath getLobbyPathForTable(Table table) {
        return new LobbyPath(table.getMetaData().getGameId(), "", table.getId());
    }

    [...]
}

As you can see above the creation participant sets the Game object on the table when it is created. It also sets a lobby attribute with the game ID which is important for the client to find the table. The lobby path above is kept simple for this example and the TABLE_STATE_ATTRIBUTE is a constant you can define yourself.

Now we need to close the table when it isn’t used. This is somewhat outside the scope of this post, but I’ll post some pseudo code here to demonstrate table destruction:

public void checkTables() {
    TableFactory fact = context.getTableFactory();
    for (LobbyTable table : fact.listTables()) {
        int tableId = table.getTableId();
        long lastModified = getLastModifiedFromAttributes(table);
        int seated = getSeatedFromAttributes(table);
        if(seated == 0 && isOld(lastModified)) {
            checkClose(tableId, table);
        }
    }
}

The above should be called regularly from a scheduled task. The “get from attributes” method are trivial, for example:

private long getLastModifiedFromAttributes(LobbyTable table) {
    Map map = table.getAttributes();
    AttributeValue a = map.get(DefaultTableAttributes._LAST_MODIFIED);
    return a.getDateValue().getTime();
}

The attributes “last modified” and “seated” are standard attributes and always available. The “table state” attribute is not and you’d have to set and get it yourself. In “check close” we’ll check the table state, destroy it if it is closed and if not, send an action to the table in order to clsoe it:

private void checkClose(int tableId, LobbyTable table) {
    TableFactory fact = context.getTableFactory();
    String state = getTableStateFromAttributes(table);
    if(state.equals("CLOSED")) {
        // the table is closed, so destroy
        fact.destroyTable(tableId, true);
    } else {
        sendCloseActionToTable(tableId);
    }
}

And finally, the method to send a “close youself” action to the table would look something like this:

private void sendCloseActionToTable(int tableId) {
    ActivatorRouter router = context.getActivatorRouter();
    CloseTableAction action = // create your action here
    byte[] actionBytes = // convert action to bytes
    GameDataAction wrap = new GameDataAction(-1, tableId);
    wrap.setData(ByteBuffer.wrap(actionBytes));
    router.dispatchToGame(tableId, wrap);
}

Which should be more or less self-explainable. The action is of course whatever type of object and encoding you use in your game, it could be standard Java objects and Serialization for example.

Table Play / Closing
The table should work as usual, the only thing we’ll add is to save the game state on the “close table command”. We need to translate the action byte data to an object, then differ between internal actions and client actions and process. Something like this perhaps (again from my Kalaha game):

public void handle(GameDataAction action, Table table) {
    Object act = // translate to action object
    log.debug("Got action: " + act);
    if(act instanceof KalahaAction) {
        // here's where you'll handle the actual game state
    } if(act instanceof CloseTableAction) {
        setTableClosedAttribute(table);
        saveTableStateToDb(table);
    } else {
        log.warn("Unknown action: " + act);
    }
}

In the above all kalaha actions are treated separately as client actions and the “close table” action simple sets the table state attribute to “CLOSED” to mark for the activator that the table is safe to remove, and then saves the game state to database.

Conclusion
As you can see, the actual code to manage asynchronous games in Firebase is minimal, you’re going to spend infinitely more time on game logic than state handling. All the code I’ve omitted is trivial. In fact, writing this article took me longer than implementing the feature in my game!

Which ends our discussion about asynchronous games in Firebase. Last post we looked at motivation and background, and in this post we’ve seen how to actually program it in Firebase. Now go and try it yourself!

Asynchronous Games in Firebase; pt I

March 11th, 2010 by larsan

Since the social web started to expand, asynchronous multiplayer games seems to really have taken off. So my immediate question is obviously, can I do that on Firebase? And the short answer is: of course. For the long answer, please read on.

Let’s recap first. In a traditional synchronous game you play against other people in real-time, everyone you play against will have to be online at the same time. But given the nature of our everyday Internet use, a different pattern has emerged: in asynchronous games not all players have to be online at the same time. For example, turn-based games can easily be made asynchronous, you play your turn and then sometime in the future you opponents will have been online and performed their moves. As such, a classic game such as chess in play-be-email mode is a prime example of an asynchronous game. But you’re not limited to turn-based games, you can define the order to act on time or any metric you’d like, the only mandatory feature is that all players do not have to be online at the same time.

Firebase is fundamentally a synchronous multiplayer server. The technical difficulties Firebase set out to solve are all issues arising from the kind of distributed computing you get when a couple of thousand players have to interact in real-time. So normally you’d build an asynchronous game on a traditional web platform, as the demand on timely updates just got a lot less urgent standard web techniques can be easily applied. But having said that, is there anything you’d gain by using Firebase?

I believe there is: A synchronous option. Easy to overlook, this is actually a big one. If you build your asynchronous game on Firebase from the start, you have an immediate option of including synchronous play. Or better yet, the difference between synchronous and asynchronous could be a simple configuration issue. And by the way, who says it’s either or? Why not both?

Let me explain the above in an example: At the moment I’m hacking on a Kalaha game for Facebook on my past-time. And obviously it’ll be asynchronous, players will take their turn while logged in, and the game mechanics will inform you of your move via the Facebook streams. But if two players are online at the same time and want to play against each other, why shouldn’t they? And would quick matches be fun, say max 5 seconds per move? And how about tournaments?

Here’s some other, perhaps minor, points to consider:

  • Duplex communication: implicit in the entire discussion is that Firebase can push events both ways from and to clients and server. In HTTP you’re forced to use Comet patterns, whereas Firebase uses a persistent connection and any actions are delivered to the clients immediately.
  • Latency: Just because you’re building an asynchronous game doesn’t automatically mean latency is not important. If your game is based on actions against a common notion of time, you might be interested in latency anyway. Firebase has an very low latency compared to most application/web servers.
  • Bandwidth: If it turns out you have a hugely successful game, and a large portion of the traffic is made up of game data (as opposed to actual web pages or other contextual data) you’ll be happy just to avoid the HTTP headers and the overhead they automatically bring to the table. Firebase uses TCP only at the moment, thus dramatically reducing the bandwidth requirements.

There are other less apparent options as well, but lets be honest, anything but a huge advantage would probably be negated by the additional platform with the integration and administration it’d mean. That is to say, if you can built it using standard web tools only, why add another platform with which to communicate, integrate and administrate?

So that’s my declaration: Using Firebase gives you the entire range from highly synchronous to entirely asynchronous on one platform! Next post I’ll sketch a proposal on how to actually do it as well. Stay tuned!

Script Support in Firebase

March 10th, 2010 by larsan

Now we have released a candidate for script support in Firebase! This is something we’re very excited about as it means no more Java (unless you want to of course, old hands like me aren’t likely to change in a hurry).

This is a first release so there’s no support for tournaments or services yet. But is not far off.

We’re using Java’s built in scripting support under the hood. It turned out to be not to trivial, but not very hard either. The interesting issues are likely to arrive when we start optimizing and bug hunting. And speaking of optimizing, I ran a few bots, say 50, against a very small script (basically the equivalent of a hello world) and on avarage the bots returned on 10 ms. That’s 10 ms for network latency, Firebase internals, and script evaluation for each event. Pretty damn good! Next step there will be to start optimizing depending on the script implementation, cashing compiled scripts, mutli-threading etc.

One major up-shot of writing on a script language and re-evaluating the script for each event is the velocity: you don’t have to restart Firebase when you change code, the script is re-evaluated automatically. The round-trip time is cut dramatically!

And… You want to see code? Here’ you are, this is the server part of the Hello World tutorial, written in…

JavaScript:

function handleDataAction(action, table) {
    _log.debug('Entering handleDataAction');
    var data = _support.getActionDataAsUTF8(action);
    var playerId = action.getPlayerId();
    var outAction = _support.newGameDataAction(playerId, table);
    _support.setActionDataAsUTF8(outAction, data);
    table.getNotifier().notifyAllPlayers(outAction);
    _log.debug('Exiting handleDataAction');
}

Ruby…

def handleDataAction(action, table)
    $_log.debug("Entering handleDataAction")
    data = $_support.getActionDataAsUTF8(action)
    playerId = action.getPlayerId()
    outAction = $_support.newGameDataAction(playerId, table)
    $_support.setActionDataAsUTF8(outAction, data)
    table.getNotifier().notifyAllPlayers(outAction)
    $_log.debug('Exiting handleDataAction')
end

Python…

def handleDataAction(action, table):
    _log.debug("Entering handleDataAction")
    data = _support.getActionDataAsUTF8(action)
    playerId = action.getPlayerId()
    outAction = _support.newGameDataAction(playerId, table)
    _support.setActionDataAsUTF8(outAction, data)
    table.getNotifier().notifyAllPlayers(outAction)
    _log.debug('Exiting handleDataAction')

Groovy…

def handleDataAction(action, table) {
    _log.debug('Entering handleDataAction')
    data = _support.getActionDataAsUTF8(action)
    playerId = action.getPlayerId()
    outAction = _support.newGameDataAction(playerId, table)
    _support.setActionDataAsUTF8(outAction, data)
    table.getNotifier().notifyAllPlayers(outAction)
    _log.debug('Exiting handleDataAction')
}

Cool, eh?

You’ll notice some strange objects above. We bound some helper objects in the evaluation context, “_log” a Firebase Log4j logger, “_support” a tool for string to byte conversion etc, and some other helpful stuff.

The JavaScript Hello World can be found here.And tentative documentation here. Have fun!

Guice Support in Firebase

March 4th, 2010 by larsan

I’ve always wanted to add dependency injection support to Firebase, and today we released a candidate for Guice! And if you ask me, it’s very cool indeed.

The documentation is a bit sparse at the moment, but can be found on our wiki. The rest of the post I’ll just show how a small fictional game would look using Guice.

To start with, the Guice support comes in a set of abstract base classes, one for each Firebase artefact. And to use those you’d have to add a dependency to you Maven build (I’ll assume Maven here, you can of course use whatever you’d like):

<dependency>
  <groupId>com.cubeia.firebase</groupId>
  <artifactId>guice-support</artifactId>
  <version>1.0-RC.1</version>
</dependency>

And if you haven’t already got it, you’d need our repository as well:

<repository>
  <id>cubeia-nexus</id>
  <url>http://m2.cubeia.com/nexus/content/groups/public/</url>
  <releases>
    <enabled>true</enabled>
  </releases>
  <snapshots>
    <enabled>true</enabled>
  </snapshots>
</repository>

Now your all set to go, just extend GuiceGame and return the class of you game processor within the configuration, like so:

public class MyGame extends GuiceGame {
    public Configuration getConfigurationHelp() {
        return new ConfigurationAdapter() {
            public Class getGameProcessorClass() {
                return MyProcessor.class;
            }
        }
    }
}

So what’s the magic then? It is this: The class MyProcessor will be instantiated by Guice and can therefore contain injections. And further, it will be done in a custom scope, per event, thus isolating instances nicely.

You can also add your own modules to the injection context, again by overriding a method in GuiceGame:

protected void preInjectorCreation(List list) {
    list.add(new MyGameModule());
}

Which means, you can inject not only stuff from the current table but also, your own classes. So if we continue:

public class MyProcessor implements MyProcessor {

    /*
     * This is probably configured in the "MyGameModule" configured
     * in the guice game extension.
     */
    @Inject
    private MyHandler handler;

    /*
     * This is a speciality, you can inject Firebase services
     * right into your classes.
     */
    @Service
    private ScriptSupport support;

    /*
     * And another shortcut, if you use Log4j, we have a
     * a helper annotation for you...
     */
    @Log4j
    private Logger log;

    public void handle(GameDataAction action, Table table) {
        // do something here eh?
    }

    [...]

}

That should give you the idea. You can inject Firebase services as well as a logger (and remember, if you don’t use Log4j, Guice support the Java utility logging package from scratch). There’s a couple of things not shown here, for example, you can inject table members directly into the classes and the state object, so you don’t have to pass those around.

Any catch? Well, when you create your own modules you’ll need to keep in mind that the processor will only work in a custom scope, called EventScope. So if you have something which needs to be bound not as a singleton or in the default scope, you’ll probably need to do something like this:

bind(MyHandler.class).to(MyHandlerImpl.class).in(EventScoped.class);

And that’s it! In a few days we’ll release our script support, which is as you might imagine built on top of the Guice support. And so far? I love it!

A Google Analytics Plugin for Nexus

February 11th, 2010 by larsan

Since Firebase Community Edition uses Maven heavily, I realized I’d like to track our Nexus repository in Google Analytics. The Nexus Book says that there exists such a plugin already, but apparently now one knows where it is. So here’s my attempt to write a simple one.

If you’re an impatient kind, here’s the source code.

I created the project  in Eclipse, instructions here.

Now, let’s start off with a “repository customizer” which is Nexus extension point we’ll use to insert a custom request processor into every repository…

public class GaTrackerRepositoryCustomizer implements RepositoryCustomizer {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @Inject
    @Named("gaTracker")
    private RequestProcessor gaTracker;

    @Override
    public void configureRepository(Repository rep) throws ConfigurationException {
        log.debug("Attaching tracker to: " + rep.getName());
        rep.getRequestProcessors().put("gaTracker", gaTracker);
    }

    @Override
    public boolean isHandledRepository(Repository rep) {
        boolean b = true;
        log.info("Handles repository '" + rep.getName() + "': " + b);
        return b;
    }
}

Not too complicated. We’re using injection to get hold of the actual tracker components and we’re inserting it into all repostories.

Wait, all repositories? Yes, and it’s problem I haven’t really figured out yet. Ideally I’d like to track “hosted” repositories only. However, we’ve configured all our builds to use a few common development “groups” for convenience. However, Nexus seems to treat groups as first class members, so even though an artifact may be deployed in a hosted repository while accessed through a group, the request processor will not get notified for the hosted repository, only the group. I tend to see “groups” as equivalent to “views” in which case I’d expect the hosted repository to be called as well, but, no…

Now, let’s create a request processor which will react when someone “reads” a path in a repository.  We’ll take it in pieces…

@Named("gaTracker")
public class GaTrackerRequestProcessor implements RequestProcessor {

    public static final String GA_TRACKER_ID =
        System.getProperty("cubeia.nexus.gaTrackerId");
    public static final String GA_REFERER_URL =
        System.getProperty("cubeia.nexus.gaRefererUrl");

    private final Logger log = LoggerFactory.getLogger(getClass());
    private final JGoogleAnalyticsTracker tracker;

    public GaTrackerRequestProcessor() {
        if(GA_TRACKER_ID == null) {
            String msg = "Missing system property 'cubeia.nexus.gaTrackerId'";
            throw new IllegalStateException(msg);
        }
         log.info("Creating new tracker, with id: " + GA_TRACKER_ID);
        tracker = new JGoogleAnalyticsTracker("nexus", "read", GA_TRACKER_ID);
        checkRefererUrl();
        adaptLogging();
    }

    [...]

We configure the plugin via system properties (not too beautiful, I know), the “tracker id” is the google tracking code id and is mandatory, and the “refer url” will be set on the call to GA if available.  We’re using the JGoogleAnalytics library to call GA for us. Also, I’m being naughty and throwing an illegal state exception if the tracker id is missing, since GA updates every 24 hours we’d like to be notified on errors early.

There’s  two methods above, one sets the logging in the tracker code to use to slf4j logger instead and the other checks for and sets the referer URL:

private void adaptLogging() {
    /*
     * Adapt the logging to use slf4j instead.
     */
    tracker.setLoggingAdapter(new LoggingAdapter() {

        public void logMessage(String msg) {
            log.debug(msg);
        }

        public void logError(String msg) {
            log.error(msg);
        }
    });
}

private void checkRefererUrl() {
    if(GA_REFERER_URL != null) {
        /*
         * If we have a referer URL we need to set this. However, the
         * tracker does not have a getter for the URL binding strategy, so
         * we'll simply create a new one, ugly, but works.
         */
        log.info("Modifying GA tracking to use referer URL: " + GA_REFERER_URL);
        GoogleAnalytics_v1_URLBuildingStrategy urlb;
        urlb = new GoogleAnalytics_v1_URLBuildingStrategy("nexus", "read", GA_TRACKER_ID);
        urlb.setRefererURL("http://m2.cubeia.com");
        // set new referer
        tracker.setUrlBuildingStrategy(urlb);
    }
}

Not too complicated eh? The only thing to note is that the only way to set the refer URL isby creating a new URL building strategy. Well, I can live with that.

Before we go on we’ll create a small subclass on FocusPoint which we’ll use for tracking. Since JGoogleAnalitycs is made primarily for applications the focus point will URL encode itself, however, that won’t work for us, so we need to override it’s getContentURI method:

/**
 * Simple inner class that adapts the content URI to
 * not be URL-escaped.
 */
private static class Point extends FocusPoint {

    public Point(String name) {
        super(name);
    }

    @Override
    public String getContentURI() {
        return getName();
    }
}

And finally we’ll tie it all toghether. We’ll react on “read” actions, create a URI (of form ‘//path’) and track asynchronously (which will spawn a new thread for calling GA:

 public boolean process(Repository rep, ResourceStoreRequest req, Action action) {
    if(action == Action.read) {
        /*
         * 1) create path by appending repo path to repo id
         * 2) create a subclass of focus point that handles proper URI's
         * 3) track asynchronously, this will perform the tracking on a new thread
         */
        String path = rep.getId() + req.getRequestPath();
        log.debug("Tracking path: " + path);
        FocusPoint p = new Point(path);
        tracker.trackAsynchronously(p);
    } else {
        log.debug("Ingoring action '" + action + "' for: " + req.getRequestPath());
    }
    return true;
}

And that’s it. It’s not perfect though ideally I’d like to track hosted repositories only, I’d like to avoid tracking crawlers and I would prefer not to configure via system properties (hint for you Nexus bundle users out there, you can set system properties in the “conf/wrapper.conf” files), but I’ll leave those for a rainy day.

Here’s the source code as a Maven project.

Enjoy!

Update: If you download and try to compile, you will probably be missing the JGoogleAnalytics lib. You’re welcome to use our, GA-tracked, repository if you like :-)

<repository>
  <id>cubeia-nexus</id>
  <url>http://m2.cubeia.com/nexus/content/groups/public/</url>
  <releases>
    <enabled>true</enabled>
  </releases>
  <snapshots>
    <enabled>true</enabled>
  </snapshots>
</repository>

Problems with Comments + Flash

February 10th, 2010 by larsan

For some reason I can’t seem to comment at the moment. So if you’re experiencing problems, please bear with us.

In the last post, netsql asked about action script support (as upposed to Flex) for Firebase, and I’ll post my answer here for the time being: Good point, it should be documented. As far as I know, but I’m no Flash coder, the API is the same. So you should be able to download it and then use the Flex examples to find your way.

Drop me a line (lars.j.nilsson at cubeia dot com) and I’l let you know when we have something up on the wiki. Otherwise just hang around, we’ll get it updated in the next few days.

Update: Oh, apparently commenting is on again.

Write a multiplayer game in 10 minutes or less!

February 10th, 2010 by larsan

As I was surfing along the other day it struck me that one of the coolest things about Firebase Community Edition is how incredibly fast you can get going. Do you think the title is a boast? Well, in a manner of speaking it is,  you see: we’re using Maven to build, and if you haven’t used Maven to build a Flex/Flash client before, Maven is going to start with downloading half of the Internet for you, and that will inevitably slow you down and may take a few minutes. But hear me! If you have used Maven before, and if you allow for the first time Maven will download the artifacts needed to compile the Firebase game and the Flex client, then I stand firm: you will have a Flex client and a Java server going in less than 10 minutes!

Do you want to get started on a multiplayer game really, really fast? Here’s two different ways:

  • The Extreme Quick Start – This hard-core, and Maven only, quick start will have you up in less than 5 minutes (excluding Maven download times). It does not however, send actual game actions between the client and the server, all you can do is join/leave tables and chat with other players… Excuse me? All you can do?! It’s completely awesome if you ask me.
  • The Beloved Hello World – This tutorial can be done with Maven and optionally Flexbuilder. It will explain along the way what happens, and it will also replace the Firebase standard chat with game actions (also chat) showing you how to communicate properly between game server and client. 10 minutes? Well, if you’re impatient and a fast reader, or if you do it twice you will most certainly beat the 10 minute mark.

If you ask me, and I’m obviously biased, this is extremely cool. Of course, this isn’t actually a game yet and there’s a lot more to learn before launching your own international success on Firebase, but hell, you want to write a game? Hop right to it!

Update: The commenting system seems to be behaving badly.  Even I can’t seem to comment at the moment. Please check the main blog for updates. I’ll be looking at switching blog system now…