Advanced Concepts

After writing your own simple Managed Objects you may find that you want to do more advanced operations like sending messages to other Managed Objects, receiving and understanding any message etc. This page contains short guides to help you achieve what you want to do.

Java Data Types

There are some basic Java classes that are important to know about when writing Managed Objects

P2Object

P2Object is the Java class that is the base class for all the Managed Objects in the Ponder2 environment. Whenever a Managed Object is provided in a PonderTalk message it arrives as an argument of type P2Object.

P2Objects are used extensively throughout the Ponder2 system to send messages, all PonderTalk message arguments are P2Objects. The P2Object class contains many static helper methods to wrap arguments up as P2Objects. e.g.

   1 P2Object string = P2Object.create("A string");
   2 
   3 P2Object integer = P2Object.create(23);
   4 
   5 P2Object float = P2Object.create(23.5);

P2ObjectAdaptor

A P2ObjectAdaptor is the base class for the stub code produced by the Java annotation compiler for translating PonderTalk messages into Java methods. The stub class for any Managed Object is <ManagedObjectClassName>P2Adaptor. So, for the simple Managed Object in the writing guide, the AlarmClock class has an adaptor class created at compile time called AlarmClockP2Adaptor. See the ObjectAdaptor page for more information about how this works.

@Ponder2op

While not strictly a Java data type, it is an important part of writing the Java Managed Object. The @Ponder2op annotation is used to tie a PonderTalk message to a Java method. The annotation is placed immediately in front of the method. It takes a single string as its argument being the PonderTalk message name. Note there is no semi-colon allowed after the Ponder2op annotation. e.g.

   1 @Ponder2op("at:put:")
   2 public void add(String aName, P2Object aManagedObject) { ... }
   3 
   4 @Ponder2op("+")
   5 public void add(String value) { ... }

In the above example, the PonderTalk message name is at:put: which is a keyword message that takes two arguments (the colon characters are very important here). The compiler matches the two keyword arguments to the two method arguments and writes code into the stub adaptor class that maps the at:put:` call to a call to the (in this case) add method and it converts the PonderTalk arguments to the correct types e.g. String and P2Object.

The second case is an example of a binary message with therefore takes one and only one arguement.

Thus the following PonderTalk will be handled correctly:

   1 myobj at: "Fred" put: root/mydomain/anotherobject.
   2 
   3 myobj + "Some string".

In fact this would also work should a number be used for the at: argument rather than a string because the number would be transparently converted to a string and then passed to the method. Should any argument not be able to be converted to the expected type an error will be thrown before the method can be called. This means that the Java Managed Object does not have to deal with errors of this kind which makes the programming easier.

Ponder2Exception

This class acts as a base class for three exception classes: Ponder2ArgumentException, Ponder2OperationException and Ponder2RemoteException. None of these exceptions need be caught by a Java Managed Object by a managed object's methods may throw one or more of them as appropriate. They are dealt with by the overall Ponder2 system.

Ponder2ArgumentException

This exception is thrown if there is something wrong with the arguments. Typically it is to o with the conversion of the PonderTalk arguments to the types required by the method. Efforts are made by the system to convert the arguments if possible but sometimes this fails. E.g. if an integer is expected and a string is given then if it can be converted to a number it is, otherwise a Ponder2ArgumentException is thrown. After this exception is thrown, the current PonderTalk filename, line number and character number are added to the exception.

Ponder2OperationException

This exception is thrown when something has gone wrong in a method. The argument string should include details of the error. After this exception is thrown, the current PonderTalk filename, line number and character number are added to the exception.

Ponder2RemoteException

This exception is thrown in the event of underlying communication failures. It is not produced by Managed Objects and is only included here for completeness.

Sending messages to other Managed Objects

PonderTalk messages are sent to Managed Objects using the operation method call. It is defined as:

   1 P2Object operation(P2Object source, String operation, P2Object... args) throws Ponder2Exception;

Where source is the object that sends or initiates the message, operation is the PonderTalk message identifier e.g. "at:put:" and args is an array of zero or more P2Objects. The source of the message is important for authorisation purposes.

There are two distinct cases where you need to send a message to another managed object, one is where you initiate a message as the result of an external action or event e.g. someone interacting with a GUI, a timer has expired, a file is changed, a TCP message is received from a non-Ponder2 source etc. The other is where your Managed Object has received a message from another Managed Object and as a result sends a message on elsewhere.

In the first case where the message is initiated by your Managed Object, you must include your P2Object identifier as the source of the operation. In the second case, you need to acquire the source of the message you have received and use that as the source of the operation you perform (unless you want to use your object's authorisation permissions for the operation).

As seen in the example of a simple Managed Object, no mention is made of P2Objects to keep things easy. You can write code that responds to PonderTalk messages without having to know anything about the inner workings of the Ponder2 environment. Since your Java class only has to implement an interface and can extend any class it likes, the relevant P2Objects are not normally available.

Initiating a message to another Managed Object

Your object's adaptor class containing all the PonderTalk message name to method mappings is actually the P2Object representing the instance of your Managed Object. This is because P2Object is a base class of your adaptor stub code. If you initiate an operation on another Managed Object you must use your P2Object identifier. To get your P2Object identifier you can simply include an extra argument in your object's contructor(s). Instead of something like:

   1 @Ponder2op("create")
   2 MyObject() {
   3     this.title = "An Object";
   4 }
   5 
   6 @Ponder2op("create:")
   7 MyObject(String aTitle) {
   8     this.title = aTitle;
   9 }

You need to add an extra argument called myP2Object like this

   1 @Ponder2op("create")
   2 MyObject(P2Object myP2Object) {
   3     this.myP2Object = myP2Object;
   4     this.title = "An Object";
   5 }
   6 
   7 @Ponder2op("create:")
   8 MyObject(P2Object myP2Object, String aTitle) {
   9     this.myP2Object = myP2Object;
  10     this.title = aTitle;
  11 }

The extra argument is recognised by the compiler (it must be called myP2Object and be of type P2Object) and it is filled in by the system when the object is created. It can be saved as an instance variable and used as necessary when sending messages. It is not part of the normal PonderTalk message arguments and so is not represented in the Ponder2op annotation.

Sending a message to another Managed Object as a result of receiving a message

When a message is received from another Managed Object it arrives in the form of a method call with the appropriate arguments. To get the P2Object identifier of the sender you can simply include an extra argument in your method. Instead of something like:

   1 // Set the GUI so that we can later display our data
   2 // PonderTalk: obj gui: root/guis/agui.
   3 @Ponder2op("gui:")
   4 public void setGui(P2Object guiobj) {
   5     this.gui = guiobj;
   6 }
   7 
   8 // Send the data to the GUI window
   9 @Ponder2op("dumpData")
  10 public void() {
  11     // We want to send the GUI a message but don't have the sender's P2Object id
  12 }
  13 
  14 // An example to show more than one argument
  15 @Ponder2op("at:put:")
  16 public void store(String name, String value) {
  17     myStore.add(name, value);
  18 }

You need to add an extra argument called source like this

   1 // Set the GUI so that we can later display our data
   2 // PonderTalk: obj gui: root/guis/agui.
   3 @Ponder2op("gui:")
   4 public void setGui(P2Object guiobj) {
   5     this.gui = guiobj;
   6 }
   7 
   8 // Send the data to the GUI window
   9 // operation() may throw an error, it should be passed up
  10 @Ponder2op("dumpData")
  11 public void(P2Object source) throws Ponder2Exception {
  12     gui.operation(source, "display:", P2Object.create("Some data"));
  13 }
  14 
  15 // An example to show more than one argument
  16 @Ponder2op("at:put:")
  17 public void store(P2Obect source, String name, String value) {
  18     myStore.add(name, value);
  19     // We could use source for something here
  20 }

The extra argument is recognised by the compiler (it must be the first argument and called source and be of type P2Object) and it is filled in by the system when the method is called. It can be used to "pass" the message on to another object, in which case the message source's authorisation will be used for the message. This argument is not part of the normal PonderTalk message arguments and so is not represented in the Ponder2op annotation.

Wildcard messages

There may be the case where you want to write a Managed Object that can accept any message, interpret it and perform actions based on that message. For this case the wildcard Ponder2op may be used with a method that takes a particular set of arguments. The method name may be anything but the argument prototype should be the same as:

   1 // Receive all messages here
   2 @Ponder2op(Ponder2op.WILDCARD)
   3     protected P2Object message(P2Object source, String op, P2Object... args) {
   4     P2Object result;
   5     ...
   6     return result;
   7 }

The op string contains the PonderTalk message identifier which is normally used in the Ponder2op annotations e.g. at:put:, display, + etc. etc.

ManagedObjectsAdvanced (last edited 2008-09-10 08:13:02 by KevinTwidle)