August'24: Kamaelia is in maintenance mode and will recieve periodic updates, about twice a year, primarily targeted around Python 3 and ecosystem compatibility. PRs are always welcome. Latest Release: 1.14.32 (2024/3/24)

Axon.AdaptiveCommsComponent

"Adaptive Comms Components" - can add and remove inboxes and outboxes

An AdaptiveCommsComponent is just like an ordinary component but with the ability to create and destroy extra inboxes and outboxes whilst it is running.

There are other variants on the basic component:

If your component needs to block - eg. wait on a system call; then make it a 'threaded' component. If it needs to change what inboxes or outboxes it has at runtime, then make it an 'adaptive' component. Otherwise, simply make it an ordinary component!

Adding and removing inboxes and outboxes

To add a new inbox or outbox call self.addInbox() or self.addOutbox() specifying a base name for the inbox/outbox. The created inbox or outbox is immediately ready to be used.:

actualInboxName = self.addInbox("inputData")
actualOutboxName = self.addOutbox("outputData")

You specify a name you would ideally like the inbox or outbox to be given. If that name is already taken then a variant of it will be generated. Calls to addInbox() and addOutbox() therefore return the actual name the inbox or outbox was given. You should always use this returned name. It is unwise to assume your ideal choice of name has been allocated!

To remove a box, call self.deleteInbox() or self.deleteOutbox() specifying the name of the box to be deleted:

self.deleteInbox(actualInboxName)
self.deleteOutbox(actualOutboxName)

When deleting an inbox or outbox, try to make sure that any linkages involving that inbox/outbox have been destroyed. This includes not only linkages created by your component, but any created by other components too.

Tracking resources

adaptivecommscomponent also includes an ability to track associations between resources and inboxes, outboxes and other information.

For example, you might want to associate another component (that your component is interacting with) with the set of inboxes, outboxes and any other info that are being used to communicate with it.

You can also associate particular inboxes or outboxes with those resources. This therefore allows you to map both ways: "which resource relates to this inbox?" and "which inboxes relate to this resource?"

For example, suppose a request leads to your component creating an inbox and outbox to deal with another component. You might store these as a tracked resource, along with other information, such as the 'other' component and any state or linkages that were created; and associate this resource with the inbox from which data might arrive:

def wireUpToOtherComponent(self, theComponent):
    newIn  = self.addInbox("commsIn")
    newOut = self.addOutbox("commsOut")

    newState = "WAITING"
    inLinkage  = self.link((theComponent,itsOutbox),(self,newIn))
    outLinkage = self.link((theComponent,itsInbox), (self,newOut))

    resource = theComponent

    inboxes = [newIn]
    outboxes = [newOut]
    info = (newState, inLinkage, outLinkage)
    self.trackResourceInformation(resource, inboxes, outboxes, info)

    self.trackResource(resource, newIn)

If a message then arrives at that inbox, we can easily look up all the information we might need know where it came from and how to handle it:

def handleMessageArrived(self, inboxName):
    msg = self.recv(inboxName)

    resource = self.retrieveResource(inboxName)
    inboxes, outboxes, info = self.retrieveResourceInformation(resource)
    theComponent=resource

    ...

When you are finished with a resource and its associated information you can clean it up with the ceaseTrackingResource() method which removes the association between the resource and information. For example when you get rid of a set of linkages and inboxes or outboxes associated with another component you might want to clean up the resource you were using to track this too:

def doneWithComponent(self, theComponent):
    resource=theComponent
    inboxes, outboxes, info = self.retrieveResourceInformation(resource)

    for name in inboxes:
        self.deleteInbox(name)
    for name in outboxes:
        self.deleteOutbox(name)

    state,linkages = info[0], info[1:]
    for linkage in linkages:
        self.unlink(thelinkage=linkage)

    self.ceaseTrackingResource(resource)

Implementation

AdaptiveCommsComponent's functionality above and beyond the ordinary Axon.Component.component is implemented in a separate mixin class _AdaptiveCommsable. This enables it to be reused for other variants on the basic component that need to inherit this functionality - such as the threadedadaptivecommscomponent.

When adding new inboxes or outboxes, name clashes are resolved by permuting the box name with a suffixed unique ID number until there is no longer any clash.

Test documentation

Tests passed:

  • -Acceptance Test - Check Addition and Deletion of Inboxes
  • -Acceptance Test - Check Addition and Deletion of Outboxes
  • __init__ - Called with with arguments does not cause problems
  • __init__ - Called with no arguments is expected, results in component superconstructor being called. performs no local initialisation
  • addInbox - adding an inbox with an existing name results in an inbox being created/added with a similar name - same name with a suffix
  • addInbox - adding an inbox with a completely new name results in that inbox being created/added
  • addOutbox - adding an outbox with an existing name results in an outbox being created/added with a similar name - same name with a suffix
  • addOutbox - adding an outbox with a completely new name results in that outbox being created/added
  • deleteInbox - KeyError exception raised if you try to delete an inbox that does not exist - this includes the case of an already deleted Inbox
  • deleteInbox - Deletes the named inbox
  • deleteOutbox - KeyError exception raised if you try to delete an outbox that does not exist - this includes the case of an already deleted Outbox
  • deleteOutbox - Deletes the named outbox
  • trackResourceInformation, retrieveTrackedResourceInformation - Tracking invalid inboxes using a resource fails.
  • trackResourceInformation, retrieveTrackedResourceInformation - Tracking invalid outboxes using a resource fails.
  • trackResourceInformation, retrieveTrackedResourceInformation - Associates communication & user aspects related to a resource. Associating default in/out boxes with a resource is valid
  • trackResourceInformation, retrieveTrackedResourceInformation - Associates communication & user aspects related to a resource. Associating dynamically created in/out boxes with a resource is the default
  • trackResource,retrieveTrackedResource - Tracking resources using an invalid inbox name should fail.
  • trackResource,retrieveTrackedResource - Adds to & retrieves from the mapping of inbox -> resource to a local store. This allows retrieval of the resource based on which inbox messages arrive on. Whilst designed for custom inboxes, it should work with the 'default' inboxes for a component
  • trackResource,retrieveTrackedResource - Tracking resources using a custom dynamic inbox name should work.

Axon.AdaptiveCommsComponent.AdaptiveCommsComponent

class AdaptiveCommsComponent(Axon.Component.component, _AdaptiveCommsable)

Base class for a component that works just like an ordinary component but can also 'adapt' its comms by adding or removing inboxes and outboxes whilst it is running.

Subclass to make your own.

See Axon.AdaptiveCommsComponent._AdaptiveCommsable for the extra methods that this subclass of component has.

Methods defined here

__init__(self, *args, **argd)

Methods inherited from Axon.Component.component :

Methods inherited from Axon.Microprocess.microprocess :

Methods inherited from Axon.AdaptiveCommsComponent._AdaptiveCommsable :

Axon.AdaptiveCommsComponent._AdaptiveCommsable

class _AdaptiveCommsable(object)

Mixin for making a component 'adaptable' so that it can create and destroy extra inboxes and outboxes at runtime.

Methods defined here

__init__(self, *args, **argd)

_newInboxName(self[, name])

Allocates a new inbox with name based on the name provided.

If this name is available it will be returned unchanged. Otherwise the name will be returned with a number appended

_newOutboxName(self[, name])

Allocates a new outbox name based on the name provided.

If this name is available it will be returned unchanged. Otherwise the name will be returned with a number appended

addInbox(self, *args)

Allocates a new inbox with name based on the name provided. If a box with the suggested name already exists then a variant is used instead.

Returns the name of the inbox added.

addOutbox(self, *args)

Allocates a new outbox with name based on the name provided. If a box with the suggested name already exists then a variant is used instead.

Returns the name of the outbox added.

ceaseTrackingResource(self, resource)

Stop tracking a resource and release references to it

deleteInbox(self, name)

Deletes the named inbox. Any messages in it are lost.

Try to ensure any linkages to involving this outbox have been destroyed - not just ones created by this component, but by others too! Behaviour is undefined if this is not the case, and should be avoided.

deleteOutbox(self, name)

Deletes the named outbox.

Try to ensure any linkages to involving this outbox have been destroyed - not just ones created by this component, but by others too! Behaviour is undefined if this is not the case, and should be avoided.

retrieveTrackedResource(self, inbox)

Retrieve the resource that has been associated with the named inbox.

retrieveTrackedResourceInformation(self, resource)

Retrieve a tuple (inboxes, outboxes, otherdata) that has been stored as the specified resource.

trackResource(self, resource, inbox)

Associate the specified resource with the named inbox.

trackResourceInformation(self, resource, inboxes, outboxes, information)

Store a list of inboxes, outboxes and other information as the specified resource.

The inboxes and outboxes specified must exist.

Feedback

Got a problem with the documentation? Something unclear that could be clearer? Want to help improve it? Constructive criticism is very welcome - especially if you can suggest a better rewording!

Please leave you feedback here in reply to the documentation thread in the Kamaelia blog.

-- Automatic documentation generator, 09 Dec 2009 at 04:00:25 UTC/GMT