The Core Behaviours

In this section, we identify the core behaviours and encapsulate them in one or more agent classes.

The Generator

If we reflect on the Generator implementation in the previous section, we can see that the real core behaviour is encoded in the first rule, which is itself entwined within coordination logic (the FIPA Request Protocol). It is easy to fix this – we simply create a new goal (the goal that is required to achieve the task), and more the code into a new rule:

  package assembly.pipeline;
  
  import assembly.LookupLibrary;
  
  agent Generator {
      module LookupLibrary library;
      module System system;

      rule +!generateCharacters(list Codes, list Letters) {
          Letters = [];
          forall (int val : Codes) {
              if ((32 <= val) & (val <= 126)) {
                  Letters = Letters + [library.toCharacter(val)];
              } else {
                  system.fail();
              }
          }
      }
  }

Remember, this is the pure behaviour at the heart of the generator task. We do not consider how this behaviour is used. That said, a simple test program can be useful:

  package assembly.pipeline;
  
  agent GeneratorTest extends Generator {
      module Console console;
  
      rule +!main(list args) {
          !generateCharacters([ 104, 101, 108, 108, 111 ], list Letters);
          console.println(Letters);
      }
  }

The Assembler

The assembler is perhaps the most interesting of the three agents as its behaviour is (intentionally) the most complex. As we discussed above, the core behaviour of this agent is the recursive creation of the string.

  package assembly.pipeline;
  
  agent Assembler {
      rule +!assemble( int Id, int Index, string String ) {
          if ( assemble( Id, Index, char Letter ) ) {
              !assemble( Id, Index + 1, String + Letter );
          } else {
              +done( Id, String );     
          }
      }
  }

We have simplified the above behaviour by removing the context from the rule. This context was constraining this behaviour to only be applied if the agent believed that it was assembling a string with a given id for a given agent. The name of the agent represents coordination information and therefore is not relevant. This should be checked prior to the execution of the above behaviour.

The main constraint on the above code is the need for the agent to have beliefs about the characters that make up the string. Again, how this is done is not the concern of this class. This is simply a pre-requisite for the use of this behaviour.

The Printer

The printer is the last, and simplest, of the three behaviours. This behaviour does one thing – it prints out the string. In the previous example, this was entwined in the coodination logic. The code below extracts this from the logic.

  package assembly.pipeline;
  
  agent Printer {
      module Console console;
  
      rule +!printString(int Id, string R) {
          console.println("Result of job "+Id+" is:[" + R + "]");
      }
  }

The Benefits

The benefit of this is that the code now encapsulates the behaviour, and is independent of the coordination logic. As an exercise, we can see that this allows us to combine the behaviours more effectively. To illustrate this, the next section will present a revised version of the pipeline, but before this, lets see what happens if we create a standalone agent that can do it all:

  package assembly.pipeline;
  
  agent Standalone extends Generator,Assembler,Printer {
      rule +!processCode(int Id, list Codes) {
          !generateCharacters( Codes, list Letters );
	
          int i = 0;
          forall( char C : Letters ) {
              +assemble(Id, i, C);
              i = i + 1;
          }
          !assemble(Id, 0, "");
	
          when (done(Id, string R)) {
              !printString(Id, R);
          }
      }
  
      rule +!main(list args) {
          !processCode(1, [ 104, 101, 108, 108, 111 ]);
      }
  }

The above code implements a single agent version of the pipeline, and provides a main rule to test that it works. This has been done without changing a single line of the Generator, Assembler, or Printer code!