Friday, November 30, 2007

OSGi Services for Dynamic Applications (II)

Or: use OSGi to write a dueling card game, part 2: the Game Controller OSGi Services client
In this posting I'm going to write the Game Controller which is a client to the User Interface OSGi Services and also a client to the Card OSGi services.

The following diagram from the first posting outlines the game architecture:

The yellow triangles represent the OSGi services, the red rectangles are bundles that provide service implementations. The Game Controller is a client to the services and lives in an OSGi bundle too.

I am using OSGi Declarative Services to handle the client side of the OSGi services. I'm doing this because DS is easier than using the OSGi ServiceTracker API, and it's part of the OSGi spec.

I always find the easiest way to develop an OSGi bundle by using the Eclipse tooling that you get with the Eclipse Plugin Development Environment (download from here). With that you simply go: File -> New Project... -> Plug-in project. In the following window you simply select 'OSGi Platform' as the target platform. If you specify 'standard' it means that you won't be using any Equinox specific bits.

On the next page you can specify some details around the plugin ID, name and version. The defaults are generally fine but for this posting you won't need an activator as Declarative Services will take care of the stuff that is typically done in an activator for us, so you can deselect that option. Finally, you don't need to use any of the templates that come with Eclipse for this posting.
Hitting 'Finish' will get you an Eclipse project that is marked as a PDE project (which is an OSGi project) with a META-INF/MANIFEST.MF file which defines the attributes of the OSGi bundle.

My game bundle has two dependencies:
  • It depends on the DuelInterfaces bundle from the previous posting. All of its classes are in the game.model package, so I will be importing that package, which gives me the freedom to rename or reversion the DuelInterfaces bundle if needed.
  • Since I'm using Declarative Services it depends on a DS implementation. I'm using the one from Equinox / Eclipse, which doesn't come with Eclipse by default, you have to manually download and install it. To get it, go to the Equinox download page, select your Eclipse version (I took 3.3.1.1) and then look for the org.eclipse.equinox.ds_xxx.jar download. I downloaded this one. Then simply drop the downloaded jar file in the plugins directory of your Eclipse installation.
    Because I'm not using any specific classes from the DS implementation, I cannot use the 'Import Package' mechanism, so I've specified this bundle as a direct dependency in 'Required Plugins'.
I've entered the dependencies in my manifest, using the Eclipse manifest editor, which now looks like this.


What I want DS to do for me is tell the Game Controller when someone has registered any new Card Services in the game or when a new User Interface is registered. When a UI is added, the controller will look for another UI that is not playing a game, if there is one it will hook them up and start the game for both players. If there is no free other UI, the newly added UI will be held until another UI presents itself. This is implemented in the Controller class which contains an addUI() method like this:

public synchronized void addUI(UserInterface ui) {
  System.out.println("Adding UI for: " +
      ui.getPlayerName());
  
  if (freeUIs.size() > 0) {
    UserInterface otherUI = freeUIs.remove(0);
    
    Player p1 = new Player(otherUI, 250);
    Player p2 = new Player(ui, 250);

    // Init both UI's with players and static commands
    ui.initializeGame(p2, p1, new DrawCommand(),
        new NextPhaseCommand(), new SelfFighter(p2));
    otherUI.initializeGame(p1, p2, new DrawCommand(),
        new NextPhaseCommand(), new SelfFighter(p1));
    
    // Create a new game with all the cards available
    final Game g =
        new GameImpl(new ArrayList(cards), p1, p2);
    
    new Thread(new Runnable() {
      public void run() {
        g.play();
      }
    }).start(); // play, don't block the OSGi thread
    games.add(g);
  } else {
    freeUIs.add(ui);
  }
}


A similar, but even simpler method is called when new cards are registered, my addCard() looks like this:
public void addCard(Card card) {
  synchronized (cards) {
    cards.add(card);
  }
}


But what do I do to get my methods called when these services get registered. This is where DS comes in. I have added a DS configuration file that instantiates my Controller component and gets DS to call me back when this happens. This pattern is called Inversion of Control (IOC). I have added a DS configuration file in my Duel bundle project in OSGI-INF/controlcomponent.xml. I could really place this file anywhere in the bundle, but putting it in OSGI-INF seems to be the convention. It contains the following XML:
<component name="controller">
  <implementation class="game.Controller"/>

  <reference name="UI"
    interface="game.model.UserInterface"
    bind="addUI"
    unbind="removeUI"
    cardinality="0..n"
    policy="dynamic"/>
  <reference name="CARD"
    interface="game.model.Card"
    bind="addCard"
    unbind="removeCard"
    cardinality="1..n"
    policy="dynamic"/>
</component>


This is what tells DS to call the Controller class when a game.model.UserInterface and a game.model.Card service is registered. It defines a component called 'controller', specifies its class and service dependencies. I've set the policy to 'dynamic' so I get notified every time one of these services gets bound or unbound. Matter of fact, this component configuration file actually causes my game.Controller class to be instantiated in the first place so that's why I don't need an OSGi Activator here. DS does it for me.
There's one last handy little nugget in here. You can see that the cardinality of the service dependencies is specified. For user interfaces it's 0 or more, but for cards it's 1 or more. The latter is handy, because it makes sure that my game Controller doesn't get created before there are a few cards registered. There's no point offering a card game to play without any cards!
So as soon as there's a few cards, my game.Controller class gets created and players can make themselves known by registering a UI.

We will need to tell DS about our OSGI-INF/controlcomponent.xml file. For this I have to reference it in the META-INF/MANIFEST.MF file. Mine looks like this:
  Bundle-Name: Duel Bundle
  Bundle-SymbolicName: Duel
  Bundle-Version: 1.0.0
  Import-Package: game.model
  Require-Bundle: org.eclipse.equinox.ds
  Service-Component: OSGI-INF/controlcomponent.xml


I won't go into too much detail on the game.GameImpl class. This is an implementation of the game.model.Game interface. It's not very complicated but it's just a bit too long for a blog post; so just look at the code :)
You can get the Game Implementation class with the Duel bundle from Subversion here: http://coderthoughts.googlecode.com/svn/trunk/duel/.

We can't start the game just yet, we first need to add a Bundle with a few cards. That's what the next posting is about.

Thursday, November 29, 2007

OSGi Services for Dynamic Applications (I)

Or: use OSGi to write a dueling card game

Surprise is one of the interesting things about dueling card games. You might know Magic the Gathering or Yi-Gi-Oh, which is quite popular with kids at the moment, many others exist too. They are interesting because there is a sheer endless number of cards so you never know what card your opponent will play. On the other hand, I never really liked the fact that whoever spends the most money on them always wins. I'd rather prefer a variant with a shared deck so that player's chances are even.

I've wanted to write a little framework for a game like this for a while now and OSGi is a great technology for doing this. Its bundle architecture brings some nice modularization and especially the OSGi Services Framework allows me to plug my services in and out at runtime without having to restart other bundles that make use of my services.
In my case, I will use this to add a new sets of cards to my game without interrupting my ongoing games, the new cards will even appear straight away in any ongoing games. I will do this in one of the next postings.

So the basics of my dueling game are similar to the games above and go like this. Each player starts with 250 points, whoever hits 0 first loses. Each player plays in turn:
  1. Draw phase - generally just draw a card
  2. Standby phase - here you can cast spells and a monster. Some spells are cast on your own area or attached to one of your monsters, other spells can affect the opponent.
  3. Battle phase - now you can attack with your monsters that are on the table. The opponent can defend with any monsters that are on her side of the table. If the defence of the defender is higher than the attack of the attacker, the defender wins, and vice versa. If the defender does not have any monsters on the table, she has to take the damage, which will cause the attack amount to be deducted from her life points.
  4. Recover phase - play spells and possibly a monster if you haven't already in this turn.
The very first battle phase is skipped (as it would be unfair to attack an opponent who didn't get to play any cards yet).

Monsters and spells often have special abilities that could be tied to a particular phase. They could change the behaviour of other cards or generally disturb the order of the game.
Another feature cards in these games generally have, is some stunning artwork which, unfortunately, I won't be able to provide.

I have come up with a little architecture that looks like this:

I'm using OSGi-style diagramming here. The yellow triangles are services, the red boxes are bundles, which provide some implementations of the services, the blue box is a component which itself lives inside a bundle.

The Game Controller is a consumer of OSGi services. It consumes any number of Card services, it also consumes 2 UI services, one UI per player.
So every card is a service of its own and every user interface is a separate service instance. As long as we adhere to the Card interface we can add any cards we can think of. Also using the service approach for the UI allows us to develop the UI separately from the game and gives us the possibility to implement any type of GUI, a simple one, a fancy one, an AI player (without a screen) or maybe even a remote UI without changing the actual game.

OSGi doesn't use the static wiring for services that you can see in some other Service Oriented Architectures, in OSGi a service consumer specifies the Java interface that it is interested in, the OSGi runtime will then dynamically bind this to an available service that implements this interface. This is completely dynamic, and services could even come and go during the life time of the system. BTW I'm not going to go too much into the OSGi basics. Neil Bartlett's blog has some excellent OSGi Basics tutorials.

Let's start by diving into the the core model of the game. (BTW I would really have loved to use EMF here again, but I wanted to keep this posting focused so I'm just using the EMF Class diagram editor for the picture, and am in this case handcoding the classes) - click on the image for a clearer picture:

Entities in italics are interfaces, others are real classes. Let's look at the interfaces that define the various types of cards first. I put a few example cards in the middle. The top interface is called Action, everything you can do and every card is an action. Cards generally implement both a subclass of Action as well as the Card interface. However there are certain actions that are not a card, such as the DrawCommand and NextPhaseCommand actions.
Commands are things that can executed, usually in a particular Phase of the game. Example command cards are the ThunderBoltCard spell which directly damages the opponent, or the SkipBattlePhaseCard which ends the current Battle phase.
Fighters are things that can take part in a battle, generally monsters, but also the player himself. Modifiers can change the attack and/or defense of a Fighter.

Then there are the following classes and interfaces:
  • Game: controls the game and provides information to the various entities about the game state. Provides accessors to change the game state too.
  • Player: data class that holds player information, such as the cards she holds in her hand, table and graveyard. Also holds a reference to the UI service that this player uses and the name of the player.
  • UserInterface: this API defines the interaction with the UI. The purpose of the UI is simply to display the game state and get any input decisions (actions) from the player. The UI can also display a line of text to the user.
Since my dueling game revolves around these classes, I have put them in a separate OSGi bundle. Other bundles can participate in the game by importing these, without having to depend on any implementation bundles. This OSGi bundle is available in Subversion here. If you're using Eclipse, the easiest way to get it into your Eclipse IDE is with a Subversion client. I always use subclipse, which is extremely easy to install; instructions here.
Once you have subclipse, open the SVN Repository Exploring perspective and add the following SVN repository URL: http://coderthoughts.googlecode.com/svn/trunk/duel/. There's no need to log in, if you expand the root node, you will get the following repositories:

Just check out the DuelInterfaces project and you're done. You will then have the OSGi bundle in your local Eclipse workspace, it will be the basis for the other pieces of the game that I'll be writing next.


For more details on the DuelInterfaces classes, read their Javadoc here.

In the following few postings I will be implementing my dueling game using more OSGi bundles and services. I'll be using a mixture of OSGi Declarative Services (DS) and direct OSGi API calls for this. Besides DS and the plain API approach (which are both part of the OSGi spec) there exist a number of other technologies to work with OSGi services: Spring-OSGi, iPojo and Guice-OSGi are some of them. The nice thing is that it doesn't matter what toolkit you use as the actual service registered with OSGi conforms to the OSGi Service Spec, so you can mix-n-match all these technologies if you like.

Besides the game logic bundle, I will be writing a bundle with monster cards and another with spell cards and I'll also provide a basic UI implementation written using SWT, which looks like this:

The good thing is, it allows me to play the game and I can write a nicer GUI later if I want, without changing the rest of the code. I might at some point even want to do a GUI that runs remotely, which allows me to use my OSGi-based application as a game server that can be used by people playing the game in various locations from a browser or something like that.

As usual I'll be using the Eclipse IDE and Equinox OSGi implementation, but nothing in the code is tied to these so please use your IDE and OSGi implementation of choice.