class NodeDef: """ The Planning Tool's node definition. """ # some code word code = attr(str) # human-readable description = attr(str) # NODE/ROOT/NID nature = attr(str, nullable=False) required(nature) functionalBlocks = refs(inv=FunctionalBlock.nodeType) descend(functionalBlocks) name = attr(str, nullable=False) motes = refs() nsd = ref() ns_nodedef = ref() # couch entities _id = attr(str) _rev = attr(str)
class Entity(Named): ''' A class modeling the entities in the project repository. ''' fields = refs() database = ref(inv=Database.entities) referents = refs() design = ref() def __init__(self, name, db): super().__init__(name) self.database = db self.idfield = Field('_id') self.revfield = Field('_rev') self.fields.add(self.idfield) self.fields.add(self.revfield) def add_foreign_key(self, name, refent): fk = ForeignKey(name, refent) self.fields.add(fk) return fk def add_field(self, name): field = Field(name) self.fields.add(field) return field def get_field(self, name): for f in self.fields: if f.name == name: return f raise KeyError("Field %s not found in entity %s" % (name, self.name))
class Named: name = attr(str, nullable=False) def __init__(self, name): self.name = name self.add_instance(self) self.implies.add(self) # An 'implies' relationship, # which is reflexive and transitive implies = refs() implied_by = refs(inv=implies) # # a <<== b means "declare that b implies a" # def __ilshift__(self, other): for p in self.implies: for q in other.implied_by: p.implied_by.add(q) return self @classmethod def add_instance(cls, obj): if not hasattr(cls, 'by_name'): cls.by_name = {} cls.by_name[obj.name] = obj def __repr__(self): return "%s(%s)" % (self.__class__.__name__, self.name)
class Design(Named): ''' A couchdb design document. ''' # the views it contains views = refs() @property def id(self): '''The document couchdb id.''' return "_design/" + self.name def to_object(self): ddoc = {'_id': self.id, 'language': 'javascript', 'views': {}} for view in self.views: ddoc['views'][view.name] = view.to_object() return ddoc def named_view(self, name): """ Return the view with the given name, or None if no such view exists. """ for view in self.views: if view.name == name: return view return None
class Field(Named): ''' A field which is compulsory in the object. ''' entity = ref(inv=Entity.fields) constraints = refs() def is_key(self): return self.name == '_id'
class CastaliaModel: ''' The top-level model, contains a ''' # omnetpp sections omnetpp = ref_list(inv=Section.castalia_model) # node types nodeTypes = refs(inv=NodeType.castalia_model) #main network definition network = attr(Network)
class Privilege(Named): ''' Represent operations on entities of a class ''' eclass = refs() def __init__(self, name): # set name and make everything included in the All # privilege super().__init__(name) global All if All is not None: self <<= All
class EClass(Named): ''' A collection of entities with common privileges ''' by_name = {} acl = ref(inv=ACL.eclass) privileges = refs(inv=Privilege.eclass) superclass = ref() subclasses = refs(inv=superclass) def __init__(self, name, superclass=None): super().__init__(name) if superclass is None: self.superclass = AnyEntity else: self.superclass = superclass self.acl = ACL() def __check_acl(self, roles, priv): d = self.acl.match(roles, priv) if d is None and self.superclass is not None: d = self.superclass.__check_acl(roles, priv) if d is None: d = False return d def authorize(self, roles, priv): '''The main method used to determine authorization.''' all_roles = set() for role in roles: all_roles.update(role.implies) return self.__check_acl(all_roles, priv) def allow(self, role, priv): self.acl.allow(role, priv) def deny(self, role, priv): self.acl.deny(role, priv)
class Network: """The object describing a Wireless Sensor Network """ def __init__(self, nsd): self.nsd = nsd # the NSD nsd = ref() # All nodes motes = refs(inv=Mote.network) def find_mote(self, node_id): """ Return a mote for the given node_id, or None if no such mote exists. """ for mote in self.motes: if mote.node_id == node_id: return mote return None
class Plan: " A PT plan object " nsd = ref(inv=NSD.plan) name = attr(str, nullable=False) NodePosition = refs(inv=Mote.plan) descend(NodePosition) # numbers numOfNodes = attr(int, nullable=False) numOfRoots = attr(int, nullable=False) numOfNidNodes = attr(int, nullable=False) # units of measurement UOMs = attr(object) connectivityMatrix = ref() # couch entities _id = attr(str) _rev = attr(str)
class Section: ''' A config section in the omnetpp.ini file ''' # the section name, or None for the general section name = attr(str, nullable=True, default=None) # the supersections (and subsections) extends = ref_list() extended_by = refs(inv=extends) # the top-level model castalia_model = ref() # module declarations for this section modules = attr(list) def __init__(self, cm, name, extends=[]): self.name = name self.castalia_model = cm self.extends = extends self.modules = []
class Database(Named): entities = refs() design = ref()
class ApiEntity(Entity): ''' An entity for which the netsim server offers a rest api. ''' # The dao api name. By default, this is # <name>_dao dao_name = attr(str, nullable=True) CheckedConstraint(LEGAL_IDENTIFIER)(dao_name) unique = refs(inv=ConstraintUnique.entity) primary_key = attr(type=ConstraintUnique, nullable=True, default=None) # fetch fields are fields that are added by the server at the API level # but not stored in the database. E.g. plan_name for NSDs fetch_fields = refs(inv=FetchField.entity) # operations supported read = attr(bool, nullable=False, default=True) create = attr(bool, nullable=False, default=True) update = attr(bool, nullable=False, default=True) delete = attr(bool, nullable=False, default=True) # A callable called to initialize new instances. # It is called with parameters (ApiEntity, obj) initializer = attr(object, nullable=False) def __init__(self, name, db, read_only=False, initializer=(lambda e, x: x), **kwargs): super().__init__(name, db) self.dao_name = kwargs.get('dao_name', "%s_dao" % name) if read_only: self.create = self.update = self.delete = False self.initializer = initializer def constraint_unique(self, name, *args): ConstraintUnique(name, self, args, primary_key=False) def set_primary_key(self, *args): if self.primary_key is not None: raise ValueError("Primary key already exists: %s" % self.primary_key.names()) self.primary_key = ConstraintUnique("%s_pk" % self.name, self, args, primary_key=True) def id_for_primary_key(self, obj): assert self.primary_key body = ":".join(str(obj[f.name]) for f in self.primary_key.fields) return "%s:%s" % (self.name, body) def create_id(self, obj): if self.primary_key: return self.id_for_primary_key(obj) else: if '_id' in obj: return obj['_id'] else: return "%s-%s" % (self.name, uuid.uuid4().hex) def initialize(self, obj): return self.initializer(self, obj) def add_fetch_field(self, name, fkey_name): fkey = [ f for f in self.fields if isinstance(f, ForeignKey) and f.name == fkey_name ] if len(fkey) != 1: raise ValueError("Cannot determine key field") fkey = fkey[0] return FetchField(name, fkey)
class NSD: ''' Network Simulation Descriptor This class encapsulates a model to be simulated. It does not contain runtime aspects of the simulation execution itself, such as simulation platform, execution engine etc. An NSD has 4 parts: parameters - a descriptor object containing simulation-related parameters environment - a descriptor object used to define the simulation of the environment, such as the measurements of the sensors application - a descriptor object defining the application simulated (network structure, node types, application logic etc) statistics - a descriptor object specifying the results generated from simulations ''' # # DPCM platform attributes # plan_id = attr(str, nullable=False) required(plan_id) project_id = attr(str, nullable=False) required(project_id) name = attr(str, nullable=False) required(name) userId = attr(str, nullable=False) plan = ref() project = ref() nodedefs = refs(inv=NodeDef.nsd) # # Application # # network object network = ref(inv=Network.nsd) hil = ref(inv=HiL.nsd) descend(hil) # # Parameters # parameters = ref(inv=Parameters.nsd) descend(parameters) # # Environment # environment = ref(inv=Environment.nsd) # # Statistics # plots = attr(list) # couch entities _id = attr(str) _rev = attr(str)