655f7e4ced420cab9b987fc6f334bf55556569e0
[nepi.git] / src / nepi / core / testbed.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # vim:ts=4:sw=4:et:ai:sts=4
4 from nepi.core.attributes import AttributesMap
5
6 class ConnectorType(object):
7     """A ConnectorType defines a kind of connector that can be used in an Object.
8     """
9     def __init__(self, connector_id, help, name, max = -1, min = 0):
10         super(ConnectorType, self).__init__()
11         """
12         ConnectorType(name, help, display_name, max, min):
13         - connector_id: (unique) identifier for this type
14         - name: descriptive name for the user
15         - help: help text
16         - max: amount of connections that this type support, -1 for no limit
17         - min: minimum amount of connections to this type of connector
18         """
19         if max == -1:
20             max = sys.maxint
21         elif max <= 0:
22                 raise RuntimeError(
23              'The maximum number of connections allowed need to be more than 0')
24         if min < 0:
25             raise RuntimeError(
26              'The minimum number of connections allowed needs to be at least 0')
27         self._connector_id = connector_id
28         self._help = help
29         self._name = name
30         self._max = max
31         self._min = min
32
33     @property
34     def connector_id(self):
35         return self._connector_id
36
37     @property
38     def help(self):
39         return self._help
40
41     @property
42     def name(self):
43         return self._name
44
45     @property
46     def max(self):
47         return self._max
48
49     @property
50     def min(self):
51         return self._min
52
53 class Connector(object):
54     """A Connector sepcifies the connection points in an Object"""
55     def __init__(self, element, connector_type):
56         super(Connector, self).__init__()
57         self._element = element
58         self._connector_type = connector_type
59         self._connections = dict()
60
61     @property
62     def element(self):
63         return self._element
64
65     @property
66     def connector_type(self):
67         return self._connector_type
68
69     @property
70     def connections(self):
71         return self._connections.values()
72
73     def is_full(self):
74         """Return True if the connector has the maximum number of connections"""
75         return len(self.connections) == self.connector_type.max
76
77     def is_complete(self):
78         """Return True if the connector has the minimum number of connections"""
79         return len(self.connection) >= self.connector_type.min 
80
81     def connect(self, connector):
82         if self.is_full() or connector.is_full():
83             raise RuntimeError("Connector is full")    
84         if not self.can_connect(connector) or not connector.can_connect(self):
85             raise RuntimeError("Could not connect.")
86         self._connections[connector._key] = connector
87         connector._connections[self._key] = self
88
89     def disconnect(self, connector):
90         if connector._key not in self._connections or 
91             self._key not in connector._connections:
92                 raise RuntimeError("Could not disconnect.")
93         del self._connections[connector._key]
94         del connector._connections[self._key]
95
96     def can_connect(self, connector):
97         raise NotImplementedError
98
99     def destroy(self):
100         for connector in self._connections:
101             self.disconnect(connector)
102         self._element = self._connectors = None
103
104     @property
105     def _key(self):
106         return "%d_%s" % (self.element.guid, self.connector_type.connector_id)
107
108 class Trace(AttributesMap):
109     def __init__(self, name, help, enabled=False):
110         super(Trace, self).__init__()
111         self._name = name
112         self._help = help       
113         self._enabled = enabled
114     
115     @property
116     def name(self):
117         return self._name
118
119     @property
120     def help(self):
121         return self._help
122
123     @property
124     def is_enabled(self):
125         return self._enabled
126
127     def read_trace(self):
128         raise NotImplementedError
129
130     def enable(self):
131         self._enabled = True
132
133     def disable(self):
134         self._enabled = False
135
136 class Element(AttributesMap):
137     def __init__(self, guid, testbed_id, factory, container = None):
138         super(Element, self).__init__()
139         # general unique id
140         self._guid = guid
141         # factory identifier or name
142         self._factory_id = factory.factory_id
143         # testbed identifier
144         self._tesbed_id = testbed_id
145         # elements can be nested inside other 'container' elements
146         self._container = container
147         # traces for the element
148         self._traces = dict()
149         # connectors for the element
150         self._connectors = dict()
151         for connector_type in factory.connector_types:
152             connector = Connector(self, connector_type)
153             self._connectors[connector_type.connector_id] = connector
154
155     @property
156     def guid(self):
157         return self._guid
158
159     @property
160     def factory_id(self):
161         return self._factory_id
162
163     @property
164     def testbed_id(self):
165         return self._testbed_id
166
167     @property
168     def container(self):
169         return self._container
170
171     @property
172     def connectors(self):
173         return self._connectors.values()
174
175     @property
176     def traces(self):
177         return self._traces.values()
178
179     def connector(self, name):
180         return self._connectors[name]
181
182     def trace(self, name):
183         return self._traces[name]
184
185     def destroy(self):
186         super(Element, self).destroy()
187         for c in self.connectors:
188             c.destroy()         
189         for t in self.traces:
190             t.destroy()
191         self._connectors = self._traces = None
192
193 class Factory(AttributesMap):
194     def __init__(self, factory_id, help = None, category = None):
195         super(Factory, self).__init__()
196         self._factory_id = factory_id
197         self._help = help
198         self._category = category
199         self._connector_types = set()
200
201     @property
202     def factory_id(self):
203         return self._factory_id
204
205     @property
206     def help(self):
207         return self._help
208
209     @property
210     def category(self):
211         return self._category
212
213     @property
214     def connector_types(self):
215         return self._connector_types
216
217     def add_connector_type(self, connector_id, help, name, max = -1, min = 0):
218         connector_type = ConnectorType(connector_id, help, name, max, min)            
219         self._connector_types.add(connector_type)
220
221     def create(self, guid, testbed_design, container = None):
222         raise NotImplementedError
223
224     def destroy(self):
225         super(Factory, self).destroy()
226         self._connector_types = None
227
228 #TODO: Provide some way to identify that the providers and the factories
229 # belong to a specific testbed version
230 class Provider(object):
231     def __init__(self):
232         super(Provider, self).__init__()
233         self._factories = dict()
234
235     def factory(self, factory_id):
236         return self._factories[factory_id]
237
238     def add_factory(self, factory):
239         self._factories[factory.factory_id] = factory
240
241     def remove_factory(self, factory_id):
242         del self._factories[factory_id]
243
244     def list_factories(self):
245         return self._factories.keys()
246
247 class TestbedDesignInstance(AttributeMap):
248     def __init__(self, guid_generator, testbed_id, provider):
249         super(TestbedInstance, self).__init__()
250         self._guid_generator = guid_generator
251         self._guid = guid_generator.next()
252         self._testbed_id = testbed_id
253         self._provider = provider
254         self._elements = dict()
255
256     @property
257     def guid(self):
258         return self._guid
259
260     @property
261     def testbed_id(self):
262         return self._testbed_id
263
264     @property
265     def elements(self):
266         return self._elements.values()
267
268     def create(self, factory_id):
269         guid = self.guid_generator.next()
270         factory = self._provider.factories(factory_id)
271         element = factory.create(guid, self)
272         self._elements[guid] = element
273
274     def delete(self, guid):
275         element = self._elements[guid]
276         del self._elements[guid]
277         element.destroy()
278
279     def instructions(self):
280         raise NotImplementedError
281
282     def destroy(self):
283         for guid, element in self._elements.iteitems():
284             del self._elements[guid]
285             element.destroy()
286         self._elements = None
287
288 class TestbedConfiguration(AttributesMap):
289     pass
290
291 class TestbedInstance(object):
292     def __init__(self, configuration):
293         pass
294
295     def execute(self, instruction):
296         #TODO:
297         pass
298
299     def execute_batch(self, batch):
300         raise NotImplementedError
301
302     def create(self, time, guid, factory_id, parameters):
303         raise NotImplementedError
304
305     def connect(self, time, connection_guid, 
306             object1_guid, object2_guid, connetor1_id, connector2_id): 
307         raise NotImplementedError
308
309     def set(self, time, guid, name, value):
310         raise NotImplementedError
311
312     def get(self, time, guid, name):
313         raise NotImplementedError
314
315     def start(self, time, guid):
316         raise NotImplementedError
317
318     def stop(self, time, guid):
319         raise NotImplementedError
320
321     def status(self, time, guid):
322         raise NotImplementedError
323
324     def enable_trace(self, time, guid, trace_id):
325         raise NotImplementedError
326
327     def disable_trace(self, time, guid, trace_id):
328         raise NotImplementedError
329
330     def get_trace(self, time, guid, trace_id):
331         raise NotImplementedError
332
333     def add_adddress(self, time, guid):
334         #TODO
335         raise NotImplementedError
336
337     def add_route(self, time, guid):
338         #TODO
339         raise NotImplementedError
340
341     def shutdown(self):
342         raise NotImplementedError
343