bugfix: can_cross and must_cross platform fixed in connetot.py
[nepi.git] / src / nepi / core / connector.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """
5 Common connector class
6 """
7
8 import sys
9
10 class ConnectorType(object):
11     def __init__(self, testbed_id, factory_id, name, help, max = -1, min = 0):
12         super(ConnectorType, self).__init__()
13
14         if max == -1:
15             max = sys.maxint
16         elif max <= 0:
17             raise RuntimeError, "The maximum number of connections allowed need to be more than 0"
18         if min < 0:
19             raise RuntimeError, "The minimum number of connections allowed needs to be at least 0"
20         # max -- maximum amount of connections that this type support, 
21         # -1 for no limit
22         self._max = max
23         # min -- minimum amount of connections required by this type of connector
24         self._min = min
25        
26         # connector_type_id -- univoquely identifies a connector type 
27         # across testbeds
28         self._connector_type_id = self.make_connector_type_id(
29             testbed_id, factory_id, name)
30         
31         # name -- display name for the connector type
32         self._name = name
33
34         # help -- help text
35         self._help = help
36
37         # from_connections -- connections where the other connector is the "From"
38         # to_connections -- connections where the other connector is the "To"
39         # keys in the dictionary correspond to the 
40         # connector_type_id for possible connections. The value is a tuple:
41         # (can_cross, connect)
42         # can_cross: indicates if the connection is allowed accros different
43         #    testbed instances
44         # code: is the connection function to be invoked when the elements
45         #    are connected
46         self._from_connections = dict()
47         self._to_connections = dict()
48
49     def __str__(self):
50         return "ConnectorType%r" % (self._connector_type_id,)
51
52     @property
53     def connector_type_id(self):
54         return self._connector_type_id
55
56     @property
57     def name(self):
58         return self._name
59
60     @property
61     def help(self):
62         return self._help
63
64     @property
65     def max(self):
66         return self._max
67
68     @property
69     def min(self):
70         return self._min
71     
72     @staticmethod
73     def make_connector_type_id(testbed_id, factory_id, name):
74         testbed_id = testbed_id.lower() if testbed_id else None
75         factory_id = factory_id.lower() if factory_id else None
76         name = name.lower() if name else None
77         return (testbed_id, factory_id, name)
78     
79     @staticmethod
80     def _type_resolution_order(connector_type_id):
81         testbed_id, factory_id, name = connector_type_id
82         
83         # the key is always a candidate
84         yield connector_type_id
85         
86         # Try wildcard combinations
87         if (testbed_id, None, name) != connector_type_id:
88             yield (testbed_id, None, name)
89         if (None, factory_id, name) != connector_type_id:
90             yield (None, factory_id, name)
91         if (None, None, name) != connector_type_id:
92             yield (None, None, name)
93
94     def add_from_connection(self, testbed_id, factory_id, name, can_cross, 
95             init_code, compl_code):
96         type_id = self.make_connector_type_id(testbed_id, factory_id, name)
97         self._from_connections[type_id] = (can_cross, init_code, compl_code)
98
99     def add_to_connection(self, testbed_id, factory_id, name, can_cross, 
100             init_code, compl_code):
101         type_id = self.make_connector_type_id(testbed_id, factory_id, name)
102         self._to_connections[type_id] = (can_cross, init_code, compl_code)
103
104     def connect_to_init_code(self, testbed_id, factory_id, name, must_cross):
105         return self._connect_to_code(testbed_id, factory_id, name, must_cross)[0]
106
107     def connect_to_compl_code(self, testbed_id, factory_id, name, must_cross):
108         return self._connect_to_code(testbed_id, factory_id, name, must_cross)[1]
109
110     def _connect_to_code(self, testbed_id, factory_id, name,
111             must_cross):
112         connector_type_id = self.make_connector_type_id(testbed_id, factory_id, name)
113         for lookup_type_id in self._type_resolution_order(connector_type_id):
114             if lookup_type_id in self._to_connections:
115                 (can_cross, init_code, compl_code) = self._to_connections[lookup_type_id]
116                 if must_cross == can_cross:
117                     return (init_code, compl_code)
118         else:
119             return (False, False)
120  
121     def can_connect(self, testbed_id, factory_id, name, must_cross):
122         connector_type_id = self.make_connector_type_id(testbed_id, factory_id, name)
123         for lookup_type_id in self._type_resolution_order(connector_type_id):
124             if lookup_type_id in self._from_connections:
125                 (can_cross, init_code, compl_code) = self._from_connections[lookup_type_id]
126             elif lookup_type_id in self._to_connections:
127                 (can_cross, init_code, compl_code) = self._to_connections[lookup_type_id]
128             else:
129                 # keep trying
130                 continue
131             return not must_cross or can_cross
132         else:
133             return False
134