Participant creation

Init, prolog and epilog

To create a customized participant, you must begin by creating a python module prefixed by "object_".

In this module, you create a new class named "Participant" and inheriting "LINC.Lib.object_basic.Participant"

(or a sub-class such as "LINC.Coordinator.object_Coordinator.Participant" or "LINC.Nameserver.object_LWNameServer.Participant").

In your Participant class, you can add 3 functions to instantiate, do some init code and free specific resources.

Those functions all have the same signature, with only one argument: an array of initial context of object.

  • def object_init(self, args) Called after object building. It allows you to define variables or do some init code. Note that at this stage the bags of the object are not yet accessible.

  • def object_prolog(self, args) Called after bags creation. It allows you to fill your bags or use them in your initialization.

  • def object_epilog(self, _args) Called before object is deleted. It allows you to free variables, to close files or do any destructor code. Note that you MUST stop all threads and processes started by your object in this method. Otherwise the behaviour of your LINC application is not guaranteed on the next boot.

Pass argument to your objects

If you want to pass arguments to your objects, here is how.

Note that you can also use bags instead of arguments, which is more dynamic.

quinoa

Object1 = data.ObjectDescription()
Object1.name = "Test"
Object1.type = "Test"
Object1.port = None
Object1.host = H1
Object1.application = A1
Object1.nameserver = NameServer
Object1.params = {param.OBJECT_TRACE_LEVEL:TRACE_LEVEL,
                  "user":"test", ### your arguments go here
                  }
Object1.list_of_bags = []
LIST_OF_OBJECTS.append(Object1)

In your object

You can access these arguments in the object_init or in the object_prolog.

def object_prolog(self, args):
    """
    Called once all the bags are implemented
    """
    LINC.Coordinator.object_Coordinator.Participant.object_prolog(self, args)
    try:
        self._user = args["params"]["user"]
    except KeyError:
        self.Tracer.print_error("could not find parameter user when starting object %s", self._name)

Default bags

You can add, in participant, default bags that are added with instantiate of this object.

For that, you must overwrite the function "get_list_of_bags", catch returned list of the parent class and add it your new bags as shown below.

def get_list_of_bags(self):
    "Define default bag of object"
    list_of_bags = object_Coordinator.Participant.get_list_of_bags(self)
    import LINC.Scripts.data
    new_bag = LINC.Scripts.data.BagDescription("Customer", ("Multiset", "TupleSpace"),
                   ['name', 'location'], {})
    new_bag.object_name = "People" # Precise a object name owned
    list_of_bags.append(new_bag)
    return list_of_bags

Note that you can precise in the field 'object_name', at which level in the inheritance hierarchy the bag belongs. This information is used to sort bags in the monitoring graphic interface.

Add a custom method to your participant

A customized participant is characterized by those LINC method callable from external tools.

There are 3 types of LINC methods: public, protected or private. The difference is made using python decorator as explained next (for info on decorators you may look at [http://wiki.python.org/moin/PythonDecorators]) .

Public LINC method

A public LINC method has the decorator @LINC.Lib.const.web_method(0) before its declaration.

This method has no argument.

A link of this method (without parameters) is added in the monitor interface of this object.

This type of method is used to create user web graphic interface.

A Public LINC method MUST return a value.

The returned value is a web graphic interface content. So, it can be html content of course, but also text, xml, svg or graphic binary.

This return value can be a string (or buffer) or a tuple.

If the method returns a tuple, the first field MUST be a string and the second field MUST be the mime type of the interface.

If you don't precise the mime type, the system will try to define one according to the content of the string returned.

Protected LINC method

This type of method is very similar of the Public method. the return type is the same but not the signature.

Its decorator is @LINC.Lib.const.web_method(1) or @LINC.Lib.const.web_method(2) before its declaration.

In the first case (web_method(1)), this method MUST have only one argument, a MethodArgs object. this argument object has 4 functions:

  • params.get_list_of_parameter_names() Return the list of parameters asked.

  • params.get_parameter(name) Return the value of the parameters named 'name'. Raise an exception if it doesn't exist.

  • params.get_parameter_with_default(name, default_value=None) Return the value of the parameters named 'name'.

You can precise a default value if it doesn't exist.

  • params.has_parameter(name) Return True if the parameters named 'name' exist.

In the second case (web_method(2)), this method may have several arguments. These arguments are the name expected by this method. For example, the LINC method get_values(self, name, filter) will answer to the HTTP URL : */METHOD?methodname=get_values&name=alice&filter=blue*

The main difference with a public method is where you use it.

An internal LINC method is not an entry point for user graphic interface, but a data source for scripting.

This LINC method is listed in the monitoring interface, but it has no hyper-link without no parameters..

You can use it in command line script to initialize data or to fill specific information from external tools.

This type of method can be directly called by other method of the object.

You can also use it in a javascript code of your web graphic interface to change the interface dynamically.

With AJAX scripting, you can call internal method to get data in text, xml, json or svg form to change your user interface.

Private LINC method

For this type of method, there are two differences with protected kind.

  • Its decorator is @LINC.Lib.const.web_method(3) or @LINC.Lib.const.web_method(4) before its declaration.
  • This method is not listed at all in the monitoring interface.

The first version expect (web_method(3)) a set of arguments, the second (web_method(4)) only one argument (a MethodArgs object).

builtins functions usage

To ensure security and reliability of your application, you must not use LINC.Lib.object_basic.Participant function in your code.

LINC offers you to use all functions of self.builtins field as a Builtins class (see in bottom).

You can add the decorator @LINC.Lib.const.promote_builtins() to a participant function to add it in the builtins structure.

It is used to allow to a bag to call this special function.

5-Example

import LINC.Coordinator.object_Coordinator
import LINC.Lib.const

class Participant(LINC.Coordinator.object_Coordinator.Participant):


    def object_init(self, args):
        LINC.Coordinator.object_Coordinator.Participant.object_init(self, args)
        # init code BEFORE bags are added

    def object_prolog(self, args):
        LINC.Coordinator.object_Coordinator.Participant.object_init(self, args)
        # init code AFTER bags are added

    def object_epilog(self, args):
        LINC.Coordinator.object_Coordinator.Participant.object_epilog(self, args)
        # epilog code: delete and kill

   def get_list_of_bags(self):
      "Define default bag of object"
      list_of_bags = LINC.Coordinator.object_Coordinator.Participant.get_list_of_bags(self)
      import LINC.Scripts.data
      new_bag = LINC.Scripts.data.BagDescription("Customer", ("Multiset", "TupleSpace"),
                           ['name', 'location'], {})
      new_bag.object_name = "People" # Precise a object name owned
      list_of_bags.append(new_bag)
      return list_of_bags

   @LINC.Lib.const.promote_builtins()
   def is_empty(self):
      cust_bag = self.builtins.get_bag("Customer")
      return cust_bag.get_resource_count(('*', '*'))==0

   @LINC.Lib.const.web_method(0)
   def home_people(self, _args):
      "Public method Home_People that enable to show the graphical interface"
      txt = self.builtins.get_template("interface_People.html")
      return txt

   @LINC.Lib.const.web_method(1)
   def get_list_cust(self, args):
      "Internal method using by javascript in 'home_people' that enable to get the list of customer with a name containing a given argument"
      c_name = params.get_parameter("customer_name")
      stub_cust = self.builtins.get_bag("Customer")
      list_cust = stub_cust.get_resource_list(['*', '*'], 0)
      txt = '<?xml version="1.0" encoding="ISO-8859-1"?>'
      txt += '<Nodes>'
      for rsc in list_cust:
         if(rsc[0].find(c_name)){
            txt += self.builtins.get_template("customer.xml") % {'name':rsc[0], 'location':rsc[1]}
         }
      txt += '</Nodes>'
      return txt


   @LINC.Lib.const.web_method(2)
   def get_list_cust(self, c_name):
      "Internal method using by javascript in 'home_people' that enable to get the list of customer with a name containing a given argument"
      stub_cust = self.builtins.get_bag("Customer")
      list_cust = stub_cust.get_resource_list(['*', '*'], 0)
      txt = '<?xml version="1.0" encoding="ISO-8859-1"?>'
      txt += '<Nodes>'
      for rsc in list_cust:
         if(rsc[0].find(c_name)){
            txt += self.builtins.get_template("customer.xml") % {'name':rsc[0], 'location':rsc[1]}
         }
      txt += '</Nodes>'
      return txt

Builtins Class

All functions of Builtins object accessing by participant or bag class.

builtins.get_object_name()

Return participant name associated to this builtins object.

builtins.get_object_context()

Return array of initial context of participant associated to this builtins object.

builtins.get_http_server_path()

Return http url of current container.

builtins.get_http_root()

Return http root directory for this participant associated to this builtins object.

It take value 'OBJECT_HTTP_ROOT' passed in params of object

If not precised, an exception "HTTP root directory not defined" raise.

builtins.get_file_from_http_server(filename)

Get file content associated to the participant associated to this builtins object.

builtins.get_list_of_bag_names()

Return string list of bag included in the participant associated to this builtins object.

builtins.get_bag(bag_name)

Return the bag named 'bag_name' and included in the participant associated to this builtins object.

If this bag in unknown, raise an exception.

builtins.signal_new_resources(bag_names)

Allow to throw a signal for current container that a set of bags are changed.

'bag_names' is a name list of bags impacted by this modification.

This function try to unfreeze actions associated to those bag.

builtins.call_method(object_name, method_name, args)

This function allow to call an other Linc method.

You must precise object and method name and arguments 'args' is a dictionary of parameters.

This method can be in the same current container or in a container running in other host.

builtins.start_safe_thread(callback, funct_args, thread_name)

This function allow to start the specific function callback with like the dico parameters funct_args to a background thread named thread_name.

builtins.Tracer

Handle to a trace object to add message in trace file.

This field is a Tracer object.

builtins.get_nameserver_info

This methods allows you to access the info of the nameserver to which this object registerd

returns nameserver_host, nameserver_port, nameserver_name

Tracer class

6 functions allow to add traces.

Tracer.print_trace(tracelevel, message, *args)

Add trace of 'tracelevel' level range to 0 (information) and 3 (high debug)

Tracer.print_warning(message, *args)

Add warning trace

Tracer.print_error_short(message, *args)

Add error trace without the stack (to be used outside of exception handling)

Tracer.print_error(message, *args)

Add error trace with stack trace

Tracer.print_fatal_error(message, *args)

Add error trace with stack trace and exit container

Tracer.print_debug(message, *args)

Equivalent to self.builtins.Tracer.print_warning(message, *args)

Add/Remove resources in a bag

To add or remove a resource in a bag belonging to the Participant, you need to get a local stub on the bag. Then you can directly call the bag methods as show in the two examples below.

remove resource

@LINC.Lib.const.web_method(0)
def remove_connection_A1_A2(self):
  conn = ("red", "A1", "A2")
  stub = self.builtins.get_bag("Connection")
  stream_id = stub.bagaction_openstream(conn)
  storage_id, rsc = stub.bagaction_read(stream_id)
  if(rsc != None):
    self.builtins.Tracer.print_debug("removed resource %s", rsc)
    res = stub.bagaction_get(storage_id)
    stub.bagaction_confirm(storage_id)
    return "SUCCESS"
  else:
    self.builtins.Tracer.print_debug("resource %s does not exist", conn)
    return "FAILED"

add resource

@LINC.Lib.const.web_method(0)
def add_connection_A1_A2(self):
  conn = ("red", "A1", "A2")
  stub = self.builtins.get_bag("Connection")
  storage_id = stub.bagaction_put(conn)
  stub.bagaction_confirm(storage_id)
  self.builtins.Tracer.print_debug("added resource %s", conn)
  # don't forget to signal that a new resource has been added to the abg
  self.builtins.signal_new_resources(["Connection"])
  return "done"