DCI Plugin for Eclipse

The Data, Context, and Interaction (DCI) architecture paradigm introduces the idea of thinking in terms of roles and contexts. See some of my white papers for a more detailed introduction into DCI, but for this blog article, consider the following example: a human could be modelled in object oriented programming by creating a super huge massive class which encapsulates all a humans attributes, their behaviours, etc. You would probably end up with something much too complex to be really maintainable. Think about when a human becomes a clown for a kids party; most of that behaviour has little to do with being a programmer, which is a different role which the human could play.

So, DCI looks at the problem differently than OOP and solves it by letting the data class be good at being a data class, and putting the behaviours specific to certain roles into “roles”, which in my DCI Tools for Java library are classes.

Certain roles interact with each other within a given context, such as a clown entertaining kids at a birthday party. The roles which belong to an interaction are part of the context, and in DCI the context is a class which puts data objects into specific roles, and makes them interact. The context and its roles form the encapsulation of the behaviour.

I have updated my library, so that there are two new Annotations, namely the @Context and @Role annotations. The @Context annotation is simply a marker to show that a class is a context. The @Role annotation is more important. It is placed onto the role interface class and tells the context where to find the role implementation, and additionally requires that the programmer specifically state to which context the role belongs.

The code ends up looking looking as follows. First a unit test which creates and calls the context:


    @Test
    public void testExecute() {
    	
    	//create an adult (the clown) and some children, 
    	//and let the party start...
        
    	Human adult = new Human();
        List children = new ArrayList();
        Human child = new Human();
        child.setName("Johnny");
        children.add(child);
        child = new Human();
        child.setName("Jane");
        children.add(child);

        ClownContext cc = new ClownContext(adult, children.toArray());
        cc.startParty();

        //check the party went well...
        assertEquals(0, adult.getHappiness());
        for (Human c : children) {
            assertEquals(1, c.getHappiness());
        }
    }
}

There is nothing special about the code above. It simply creates some data objects and passes them to the context, and then starts the party (the interaction, or use case). Next, the context class is shown:


/** the context in which a clown entertains some kids. */
@Context
public class ClownContext extends BehaviourInjector {

    /** the object who will play the clown role */
    private Object adult;
    
    /** the objects who will play the kid role */
    private List children;

    /**
     * Creates a new Context object. takes "objects" rather than specific types to allow it to be reusable.
     */
    public ClownContext(Object adult, Object[] children) {
        this.adult = adult;

        this.children = new ArrayList();

        for (Object child : children) {
            this.children.add(child);
        }
    }

    /** start the interaction */
    public void startParty() {
        Clown clown = assignRole(adult, Clown.class);
        
        clown.applyMakeup();

        IIterable kids = getIterable(children.iterator(), Kid.class);

        clown.makeKidsLaugh(kids);
    }

}

The context has a few noteworthy points. First of all, it extends the BehaviourInjector. By doing this, it has access to the assignRole(Object, Class) and getIterable(Iterator, Class) methods. Note the @Context annotation at the top – it’s important for not only helping the programmer spot that it’s a context, but also for the Eclipse plugin which I created and which I introduce below.

You might have spotted that the context above is not tightly coupled with the Human class. The reason is simply to make the context and its roles usable in the future, with data classes which I currently know nothing about. It is feasible that a robot might one day do parties by dressing up as a clown!

Assigning the role is where the behaviour is “injected” into the data object. The iterable which is created is a special role, which can automatically cast the human children into the role of a kid attending a party.

Next, take a look at the role interface. This class defines the methods which data object must have to play the role, as well as the behaviour which will be added to the object.


@Role(contextClass = ClownContext.class, 
	  implementationClass = ClownImpl.class)
public interface Clown {

	/** put some makeup on (initialise) */
	public void applyMakeup(); // role

	/** makes kids laugh */
	public void makeKidsLaugh(IIterable kids); // role
	
	public void setHairColour(Color c); // data
	
}

The role interface has the @Role annotation which tells the behaviour injector firstly to which context the role belongs, and secondly where the actual implementation (behaviour) can be found. In the clown role specified above, two behaviours are added (applying make up and making kids laugh). The application of make up additionally requires that the clown be able to set his hair colour, so that method which the human class must have is also specified here.

Finally, the role implementation class:


public class ClownImpl {

	@Self
	private Clown self;
	
	/** @see Clown#applyMakeup() */
	public void applyMakeup(){
		self.setHairColour(Color.GREEN);
	}

	/** @see Clown#makeKidsLaugh(IIterable) */
	public void makeKidsLaugh(IIterable kids) {
		for (Kid kid : kids) {
			kid.laugh();
			System.out.println();
		}
	}
}

The role implementation does not need to implement the role interface! It is simply a class which the behaviour injector relies upon to find behaviour which it cannot find in the data object. The @Self annotation on the clown field called self is a reference to the object playing the clown role, and is similar to “this”, just that “this” would be a reference to the instance of the role implementation, rather than the object playing the role. It allows you to access the data methods of the data object.

Now, as well as helping the programmer to mentally associate contexts with roles, these two annotations allow static analysis of the code to be performed. Using the Eclipse JDT framework, it is possible to obtain individual tokens of source code, even when the class files don’t compile, in order to build up a model of contexts and roles within a Java project. I created a little DCI Outline view for Eclipse, similar to the class outline, except rather than showing classes, it shows the contexts and their associated roles. Here’s a screen shot:

The view shows all contexts which it finds in the selected Java project. For each context, it shows the package, followed by a list of its methods, and then all the roles that belong to it.

For each role interface, the package is listed, followed by a list of methods which the role interface contains. At the bottom of a role branch, is the role implementation class.

The idea of this plugin is to give the programmer a view of what contexts are available and what roles they contain. It puts contexts, roles and their methods into the mind of the programmer letting them think in terms of DCI, exactly the same way which a standard class browser lets the programmer think in terms of classes.

Double clicking on a role interface, role implementation or context will open it in the editor.

The plugin has limited validation capabilities and can determine for example, if a context specified in a role annotation cannot be found within the project, and highlights this so that the programmer can see there is a problem. In such cases, the view looks like this:

The code from this example can be downloaded here.

A full instruction manual, together with the the DCI Tools for Java library, and the Eclipse Update site can be found at here.

Attention: No clowns were harmed during the writing of this blog.

© 2010 Ant Kutschera