Changeset 989 for trunk/common

Show
Ignore:
Timestamp:
04/03/05 10:18:47 (4 years ago)
Author:
asterix
Message:

back to previous xmlstream.py
print an error when we try to connect an inexisting server instead of crash

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/common/xmlstream.py

    r986 r989  
    4343True  = 1 
    4444 
    45 TCP      = 1 
     45TCP    = 1 
    4646STDIO   = 0 
    4747TCP_SSL = 2 
    4848 
    49 ENCODING = 'utf-8'        # Though it is uncommon, this is the only right setting. 
     49ENCODING = 'utf-8'      # Though it is uncommon, this is the only right setting. 
    5050ustr = str 
    5151 
    52 BLOCK_SIZE  = 1024      ## Number of bytes to get at at time via socket 
    53                                            ## transactions 
     52BLOCK_SIZE  = 1024    ## Number of bytes to get at at time via socket 
     53                       ## transactions 
    5454 
    5555DBG_INIT, DBG_ALWAYS = debug.DBG_INIT, debug.DBG_ALWAYS 
    56 DBG_CONN_ERROR = 'conn-error'   ; debug.debug_flags.append( DBG_CONN_ERROR ) 
    57 DBG_XML_PARSE = 'xml-parse'       ; debug.debug_flags.append( DBG_XML_PARSE ) 
    58 DBG_XML_RAW = 'xml-raw'           ; debug.debug_flags.append( DBG_XML_RAW ) 
     56DBG_CONN_ERROR = 'conn-error'    ; debug.debug_flags.append( DBG_CONN_ERROR ) 
     57DBG_XML_PARSE = 'xml-parse'      ; debug.debug_flags.append( DBG_XML_PARSE ) 
     58DBG_XML_RAW = 'xml-raw'          ; debug.debug_flags.append( DBG_XML_RAW ) 
    5959DBG_XML = [ DBG_XML_PARSE, DBG_XML_RAW ] # sample multiflag 
    6060 
    6161 
    6262def XMLescape(txt): 
    63         "Escape XML entities" 
    64         txt = txt.replace("&", "&") 
    65         txt = txt.replace("<", "&lt;") 
    66         txt = txt.replace(">", "&gt;") 
    67         return txt 
     63    "Escape XML entities" 
     64    txt = txt.replace("&", "&amp;") 
     65    txt = txt.replace("<", "&lt;") 
     66    txt = txt.replace(">", "&gt;") 
     67    return txt 
    6868 
    6969def XMLunescape(txt): 
    70         "Unescape XML entities" 
    71         txt = txt.replace("&gt;", ">") 
    72         txt = txt.replace("&lt;", "<") 
    73         txt = txt.replace("&amp;", "&") 
    74         return txt 
     70    "Unescape XML entities" 
     71    txt = txt.replace("&gt;", ">") 
     72    txt = txt.replace("&lt;", "<") 
     73    txt = txt.replace("&amp;", "&") 
     74    return txt 
    7575 
    7676class error: 
    77         def __init__(self, value): 
    78                 self.value = str(value) 
    79         def __str__(self): 
    80                 return self.value 
     77    def __init__(self, value): 
     78        self.value = str(value) 
     79    def __str__(self): 
     80        return self.value 
    8181 
    8282class Node: 
    83         """A simple XML DOM like class""" 
    84         def __init__(self, tag=None, parent=None, attrs={}, payload=[], node=None): 
    85                 if node: 
    86                         if type(node)<>type(self): node=NodeBuilder(node).getDom() 
    87                         self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = \ 
    88                                 node.name,node.namespace,node.attrs,node.data,node.kids,node.parent 
    89                 else: 
    90                         self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = 'tag','',{},[],[],None 
    91  
    92                 if tag: self.namespace, self.name = (['']+tag.split())[-2:] 
    93  
    94                 if parent: self.parent = parent 
    95  
    96 #               if self.parent and not self.namespace: self.namespace=self.parent.namespace   # Doesn't checked if this neccessary 
    97  
    98                 for attr in attrs.keys(): 
    99                         self.attrs[attr]=attrs[attr] 
    100  
    101                 for i in payload: 
    102                         if type(i)==type(self): self.insertNode(i) 
    103                         else: self.insertXML(i) 
    104 #                       self.insertNode(Node(node=i))    # Alternative way. Needs perfomance testing. 
    105  
    106         def setParent(self, node): 
    107                 "Set the nodes parent node." 
    108                 self.parent = node 
    109  
    110         def getParent(self): 
    111                 "return the nodes parent node." 
    112                 return self.parent 
    113  
    114         def getName(self): 
    115                 "Set the nodes tag name." 
    116                 return self.name 
    117  
    118         def setName(self,val): 
    119                 "Set the nodes tag name." 
    120                 self.name = val 
    121  
    122         def putAttr(self, key, val): 
    123                 "Add a name/value attribute to the node." 
    124                 self.attrs[key] = val 
    125  
    126         def getAttr(self, key): 
    127                 "Get a value for the nodes named attribute." 
    128                 try: return self.attrs[key] 
    129                 except: return None 
    130  
    131         def putData(self, data): 
    132                 "Set the nodes textual data" 
    133                 self.data.append(data) 
    134  
    135         def insertData(self, data): 
    136                 "Set the nodes textual data" 
    137                 self.data.append(data) 
    138  
    139         def getData(self): 
    140                 "Return the nodes textual data" 
    141                 return ''.join(self.data) 
    142  
    143         def getDataAsParts(self): 
    144                 "Return the node data as an array" 
    145                 return self.data 
    146  
    147         def getNamespace(self): 
    148                 "Returns the nodes namespace." 
    149                 return self.namespace 
    150  
    151         def setNamespace(self, namespace): 
    152                 "Set the nodes namespace." 
    153                 self.namespace = namespace 
    154  
    155         def insertTag(self, name=None, attrs={}, payload=[], node=None): 
    156                 """ Add a child tag of name 'name' to the node. 
    157  
    158                         Returns the newly created node. 
    159                 """ 
    160                 newnode = Node(tag=name, parent=self, attrs=attrs, payload=payload, node=node) 
    161                 self.kids.append(newnode) 
    162                 return newnode 
    163  
    164         def insertNode(self, node): 
    165                 "Add a child node to the node" 
    166                 self.kids.append(node) 
    167                 return node 
    168  
    169         def insertXML(self, xml_str): 
    170                 "Add raw xml as a child of the node" 
    171                 newnode = NodeBuilder(xml_str).getDom() 
    172                 self.kids.append(newnode) 
    173                 return newnode 
    174  
    175         def __str__(self): 
    176                 return self._xmlnode2str() 
    177  
    178         def _xmlnode2str(self, parent=None): 
    179                 """Returns an xml ( string ) representation of the node 
    180                 and it children""" 
    181                 s = "<" + self.name 
    182                 if self.namespace: 
    183                         if parent and parent.namespace != self.namespace: 
    184                                 s = s + " xmlns = '%s' " % self.namespace 
    185                 for key in self.attrs.keys(): 
    186                         val = ustr(self.attrs[key]) 
    187                         s = s + " %s='%s'" % ( key, XMLescape(val) ) 
    188                 s = s + ">" 
    189                 cnt = 0 
    190                 if self.kids != None: 
    191                         for a in self.kids: 
    192                                 if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt]) 
    193                                 s = s + a._xmlnode2str(parent=self) 
    194                                 cnt=cnt+1 
    195                 if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt]) 
    196                 if not self.kids and s[-1:]=='>': 
    197                         s=s[:-1]+' />' 
    198                 else: 
    199                         s = s + "</" + self.name + ">" 
    200                 return s 
    201  
    202         def getTag(self, name, index=None): 
    203                 """Returns a child node with tag name. Returns None 
    204                 if not found.""" 
    205                 for node in self.kids: 
    206                         if node.getName() == name: 
    207                                 if not index: return node 
    208                                 if index is not None: index-=1 
    209                 return None 
    210  
    211         def getTags(self, name): 
    212                 """Like getTag but returns a list with matching child nodes""" 
    213                 nodes=[] 
    214                 for node in self.kids: 
    215                         if node.getName() == name: 
    216                            nodes.append(node) 
    217                 return nodes 
    218  
    219         def getChildren(self): 
    220                 """Returns a nodes children""" 
    221                 return self.kids 
    222  
    223         def removeTag(self,tag): 
    224                 """Pops out specified child and returns it.""" 
    225                 if type(tag)==type(self): 
    226                         try: 
    227                                 self.kids.remove(tag) 
    228                                 return tag 
    229                         except: return None 
    230                 for node in self.kids: 
    231                         if node.getName()==tag: 
    232                                 self.kids.remove(node) 
    233                                 return node 
     83    """A simple XML DOM like class""" 
     84    def __init__(self, tag=None, parent=None, attrs={}, payload=[], node=None): 
     85        if node: 
     86            if type(node)<>type(self): node=NodeBuilder(node).getDom() 
     87            self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = \ 
     88                node.name,node.namespace,node.attrs,node.data,node.kids,node.parent 
     89        else: 
     90            self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = 'tag','',{},[],[],None 
     91 
     92        if tag: self.namespace, self.name = (['']+tag.split())[-2:] 
     93 
     94        if parent: self.parent = parent 
     95 
     96#        if self.parent and not self.namespace: self.namespace=self.parent.namespace   # Doesn't checked if this neccessary 
     97 
     98        for attr in attrs.keys(): 
     99            self.attrs[attr]=attrs[attr] 
     100 
     101        for i in payload: 
     102            if type(i)==type(self): self.insertNode(i) 
     103            else: self.insertXML(i) 
     104#            self.insertNode(Node(node=i))    # Alternative way. Needs perfomance testing. 
     105 
     106    def setParent(self, node): 
     107        "Set the nodes parent node." 
     108        self.parent = node 
     109 
     110    def getParent(self): 
     111        "return the nodes parent node." 
     112        return self.parent 
     113 
     114    def getName(self): 
     115        "Set the nodes tag name." 
     116        return self.name 
     117 
     118    def setName(self,val): 
     119        "Set the nodes tag name." 
     120        self.name = val 
     121 
     122    def putAttr(self, key, val): 
     123        "Add a name/value attribute to the node." 
     124        self.attrs[key] = val 
     125 
     126    def getAttr(self, key): 
     127        "Get a value for the nodes named attribute." 
     128        try: return self.attrs[key] 
     129        except: return None 
     130 
     131    def putData(self, data): 
     132        "Set the nodes textual data" 
     133        self.data.append(data) 
     134 
     135    def insertData(self, data): 
     136        "Set the nodes textual data" 
     137        self.data.append(data) 
     138 
     139    def getData(self): 
     140        "Return the nodes textual data" 
     141        return ''.join(self.data) 
     142 
     143    def getDataAsParts(self): 
     144        "Return the node data as an array" 
     145        return self.data 
     146 
     147    def getNamespace(self): 
     148        "Returns the nodes namespace." 
     149        return self.namespace 
     150 
     151    def setNamespace(self, namespace): 
     152        "Set the nodes namespace." 
     153        self.namespace = namespace 
     154 
     155    def insertTag(self, name=None, attrs={}, payload=[], node=None): 
     156        """ Add a child tag of name 'name' to the node. 
     157 
     158            Returns the newly created node. 
     159        """ 
     160        newnode = Node(tag=name, parent=self, attrs=attrs, payload=payload, node=node) 
     161        self.kids.append(newnode) 
     162        return newnode 
     163 
     164    def insertNode(self, node): 
     165        "Add a child node to the node" 
     166        self.kids.append(node) 
     167        return node 
     168 
     169    def insertXML(self, xml_str): 
     170        "Add raw xml as a child of the node" 
     171        newnode = NodeBuilder(xml_str).getDom() 
     172        self.kids.append(newnode) 
     173        return newnode 
     174 
     175    def __str__(self): 
     176        return self._xmlnode2str() 
     177 
     178    def _xmlnode2str(self, parent=None): 
     179        """Returns an xml ( string ) representation of the node 
     180        and it children""" 
     181        s = "<" + self.name 
     182        if self.namespace: 
     183            if parent and parent.namespace != self.namespace: 
     184                s = s + " xmlns = '%s' " % self.namespace 
     185        for key in self.attrs.keys(): 
     186            val = ustr(self.attrs[key]) 
     187            s = s + " %s='%s'" % ( key, XMLescape(val) ) 
     188        s = s + ">" 
     189        cnt = 0 
     190        if self.kids != None: 
     191            for a in self.kids: 
     192                if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt]) 
     193                s = s + a._xmlnode2str(parent=self) 
     194                cnt=cnt+1 
     195        if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt]) 
     196        if not self.kids and s[-1:]=='>': 
     197            s=s[:-1]+' />' 
     198        else: 
     199            s = s + "</" + self.name + ">" 
     200        return s 
     201 
     202    def getTag(self, name, index=None): 
     203        """Returns a child node with tag name. Returns None 
     204        if not found.""" 
     205        for node in self.kids: 
     206            if node.getName() == name: 
     207                if not index: return node 
     208                if index is not None: index-=1 
     209        return None 
     210 
     211    def getTags(self, name): 
     212        """Like getTag but returns a list with matching child nodes""" 
     213        nodes=[] 
     214        for node in self.kids: 
     215            if node.getName() == name: 
     216               nodes.append(node) 
     217        return nodes 
     218 
     219    def getChildren(self): 
     220        """Returns a nodes children""" 
     221        return self.kids 
     222 
     223    def removeTag(self,tag): 
     224        """Pops out specified child and returns it.""" 
     225        if type(tag)==type(self): 
     226            try: 
     227                self.kids.remove(tag) 
     228                return tag 
     229            except: return None 
     230        for node in self.kids: 
     231            if node.getName()==tag: 
     232                self.kids.remove(node) 
     233                return node 
    234234 
    235235class NodeBuilder: 
    236         """builds a 'minidom' from data parsed to it. Primarily for insertXML 
    237            method of Node""" 
    238         def __init__(self,data=None): 
    239                 self._parser = xml.parsers.expat.ParserCreate(namespace_separator=' ') 
    240                 self._parser.StartElementHandler  = self.unknown_starttag 
    241                 self._parser.EndElementHandler  = self.unknown_endtag 
    242                 self._parser.CharacterDataHandler = self.handle_data 
    243  
    244                 self.__depth = 0 
    245                 self._dispatch_depth = 1 
    246  
    247                 if data: self._parser.Parse(data,1) 
    248  
    249         def unknown_starttag(self, tag, attrs): 
    250                 """XML Parser callback""" 
    251                 self.__depth = self.__depth + 1 
    252                 self.DEBUG("DEPTH -> %i , tag -> %s, attrs -> %s" % \ 
    253                                    (self.__depth, tag, str(attrs)),DBG_XML_PARSE ) 
    254                 if self.__depth == self._dispatch_depth: 
    255                         self._mini_dom = Node(tag=tag, attrs=attrs) 
    256                         self._ptr = self._mini_dom 
    257                 elif self.__depth > self._dispatch_depth: 
    258                         self._ptr.kids.append(Node(tag=tag,parent=self._ptr,attrs=attrs)) 
    259                         self._ptr = self._ptr.kids[-1] 
    260                 else:                                              ## it the stream tag: 
    261                         if attrs.has_key('id'): 
    262                                 self._incomingID = attrs['id'] 
    263                 self.last_is_data = False 
    264  
    265         def unknown_endtag(self, tag ): 
    266                 """XML Parser callback""" 
    267                 self.DEBUG("DEPTH -> %i" % self.__depth,DBG_XML_PARSE) 
    268                 if self.__depth == self._dispatch_depth: 
    269                         self.dispatch(self._mini_dom) 
    270                 elif self.__depth > self._dispatch_depth: 
    271                         self._ptr = self._ptr.parent 
    272                 else: 
    273                         self.DEBUG("*** Stream terminated ? ****",DBG_CONN_ERROR) 
    274                 self.__depth = self.__depth - 1 
    275                 self.last_is_data = False 
    276  
    277         def handle_data(self, data): 
    278                 """XML Parser callback""" 
    279                 self.DEBUG("data-> " + data,DBG_XML_PARSE) 
    280                 if self.last_is_data: 
    281                         self._ptr.data[-1] += data 
    282                 else: 
    283                         self._ptr.data.append(data) 
    284                         self.last_is_data = True 
    285  
    286         def dispatch(self,dom): 
    287                 pass 
    288  
    289         def DEBUG(self,dup1,dup2=None): 
    290                 pass 
    291  
    292         def getDom(self): 
    293                 return self._mini_dom 
     236    """builds a 'minidom' from data parsed to it. Primarily for insertXML 
     237       method of Node""" 
     238    def __init__(self,data=None): 
     239        self._parser = xml.parsers.expat.ParserCreate(namespace_separator=' ') 
     240        self._parser.StartElementHandler  = self.unknown_starttag 
     241        self._parser.EndElementHandler    = self.unknown_endtag 
     242        self._parser.CharacterDataHandler = self.handle_data 
     243 
     244        self.__depth = 0 
     245        self._dispatch_depth = 1 
     246 
     247        if data: self._parser.Parse(data,1) 
     248 
     249    def unknown_starttag(self, tag, attrs): 
     250        """XML Parser callback""" 
     251        self.__depth = self.__depth + 1 
     252        self.DEBUG("DEPTH -> %i , tag -> %s, attrs -> %s" % \ 
     253                   (self.__depth, tag, str(attrs)),DBG_XML_PARSE ) 
     254        if self.__depth == self._dispatch_depth: 
     255            self._mini_dom = Node(tag=tag, attrs=attrs) 
     256            self._ptr = self._mini_dom 
     257        elif self.__depth > self._dispatch_depth: 
     258            self._ptr.kids.append(Node(tag=tag,parent=self._ptr,attrs=attrs)) 
     259            self._ptr = self._ptr.kids[-1] 
     260        else:                           ## it the stream tag: 
     261            if attrs.has_key('id'): 
     262                self._incomingID = attrs['id'] 
     263        self.last_is_data = False 
     264 
     265    def unknown_endtag(self, tag ): 
     266        """XML Parser callback""" 
     267        self.DEBUG("DEPTH -> %i" % self.__depth,DBG_XML_PARSE) 
     268        if self.__depth == self._dispatch_depth: 
     269            self.dispatch(self._mini_dom) 
     270        elif self.__depth > self._dispatch_depth: 
     271            self._ptr = self._ptr.parent 
     272        else: 
     273            self.DEBUG("*** Stream terminated ? ****",DBG_CONN_ERROR) 
     274        self.__depth = self.__depth - 1 
     275        self.last_is_data = False 
     276 
     277    def handle_data(self, data): 
     278        """XML Parser callback""" 
     279        self.DEBUG("data-> " + data,DBG_XML_PARSE) 
     280        if self.last_is_data: 
     281            self._ptr.data[-1] += data 
     282        else: 
     283            self._ptr.data.append(data) 
     284            self.last_is_data = True 
     285 
     286    def dispatch(self,dom): 
     287        pass 
     288 
     289    def DEBUG(self,dup1,dup2=None): 
     290        pass 
     291 
     292    def getDom(self): 
     293        return self._mini_dom 
    294294 
    295295 
    296296class Stream(NodeBuilder): 
    297         """Extention of NodeBuilder class. Handles stream of XML stanzas. 
    298            Calls dispatch method for every child of root node 
    299            (stream:stream for jabber stream). 
    300            attributes _read, _write and _reader must be set by external entity 
    301         """ 
    302         def __init__(self, namespace, 
    303                                 debug=[DBG_ALWAYS], 
    304                                 log=None, 
    305                                 id=None, 
    306                                 timestampLog=True): 
    307  
    308                 self._namespace = namespace 
    309  
    310                 self._read , self._reader , self._write = None , None , None 
    311  
    312                 self._incomingID = None 
    313                 self._outgoingID = id 
    314  
    315                 self._debug = _debug.Debug(debug,encoding=ENCODING) 
    316                 self.DEBUG = self._debug.show # makes it backwards compatible with v0.4 code 
    317  
    318                 self.DEBUG("stream init called",DBG_INIT) 
    319  
    320                 if log: 
    321                         if type(log) is type(""): 
    322                                 try: 
    323                                         self._logFH = open(log,'w') 
    324                                 except: 
    325                                         print "ERROR: can open %s for writing" % log 
    326                                         sys.exit(0) 
    327                         else: ## assume its a stream type object 
    328                                 self._logFH = log 
    329                 else: 
    330                         self._logFH = None 
    331                 self._timestampLog = timestampLog 
    332  
    333         def connect(self): 
    334                 NodeBuilder.__init__(self) 
    335                 self._dispatch_depth = 2 
    336  
    337         def timestampLog(self,timestamp): 
    338                 """ Enable or disable the showing of a timestamp in the log. 
    339                         By default, timestamping is enabled. 
    340                 """ 
    341                 self._timestampLog = timestamp 
    342  
    343         def read(self): 
    344                 """Reads incoming data. Blocks until done. Calls self.disconnected(self) if appropriate.""" 
    345                 try: received = self._read(BLOCK_SIZE) 
    346                 except: received = '' 
    347  
    348                 while select([self._reader],[],[],0)[0]: 
    349                         add = self._read(BLOCK_SIZE) 
    350                         received +=add 
    351                         if not add: break 
    352  
    353                 if len(received): # length of 0 means disconnect 
    354                         self.DEBUG("got data " + received , DBG_XML_RAW ) 
    355                         self.log(received, 'RECV:') 
    356                 else: self.disconnected(self) 
    357                 return received 
    358  
    359         def write(self,raw_data): 
    360                 """Writes raw outgoing data. Blocks until done. 
    361                    If supplied data is not unicode string, ENCODING 
    362                    is used for convertion. Avoid this! 
    363                    Always send your data as a unicode string.""" 
    364                 if type(raw_data) == type(''): 
    365                         self.DEBUG('Non-utf-8 string "%s" passed to Stream.write! Treating it as %s encoded.'%(raw_data,ENCODING)) 
    366                         raw_data = unicode(raw_data,ENCODING) 
    367                 data_out = raw_data.encode('utf-8') 
    368                 try: 
    369                         self._write(data_out) 
    370                         self.log(data_out, 'SENT:') 
    371                         self.DEBUG("sent %s" % data_out,DBG_XML_RAW) 
    372                 except: 
    373                         self.DEBUG("xmlstream write threw error",DBG_CONN_ERROR) 
    374                         self.disconnected(self) 
    375  
    376         def process(self, timeout=0): 
    377                 """Receives incoming data (if any) and processes it. 
    378                    Waits for data no more than timeout seconds.""" 
    379                 if select([self._reader],[],[],timeout)[0]: 
    380                         data = self.read() 
    381                         self._parser.Parse(data) 
    382                         return len(data) 
    383                 return '0'      # Zero means that nothing received but link is alive. 
    384  
    385         def disconnect(self): 
    386                 """Close the stream and socket""" 
    387                 self.write ( u"</stream:stream>" ) 
    388                 while self.process(): pass 
    389                 self._sock.close() 
    390                 self._sock = None 
    391  
    392         def disconnected(self,conn): 
    393                 """Called when a Network Error or disconnection occurs.""" 
    394                 try: self.disconnectHandler(conn) 
    395                 except TypeError: self.disconnectHandler() 
    396  
    397         def disconnectHandler(self,conn): ## To be overidden ## 
    398                 """Called when a Network Error or disconnection occurs. 
    399                 Designed to be overidden""" 
    400                 raise error("Standart disconnectionHandler called. Replace it with appropriate for your client.") 
    401  
    402         def log(self, data, inout=''): 
    403                 """Logs data to the specified filehandle. Data is time stamped 
    404                 and prefixed with inout""" 
    405                 if self._logFH is not None: 
    406                         if self._timestampLog: 
    407                                 self._logFH.write("%s - %s - %s\n" % (time.asctime(), inout, data)) 
    408                         else: 
    409                                 self._logFH.write("%s - %s\n" % (inout, data ) ) 
    410                         self._logFH.flush() 
    411  
    412         def getIncomingID(self): 
    413                 """Returns the streams ID""" 
    414                 return self._incomingID 
    415  
    416         def getOutgoingID(self): 
    417                 """Returns the streams ID""" 
    418                 return self._incomingID 
     297    """Extention of NodeBuilder class. Handles stream of XML stanzas. 
     298       Calls dispatch method for every child of root node 
     299       (stream:stream for jabber stream). 
     300       attributes _read, _write and _reader must be set by external entity 
     301    """ 
     302    def __init__(self, namespace, 
     303                debug=[DBG_ALWAYS], 
     304                log=None, 
     305                id=None, 
     306                timestampLog=True): 
     307 
     308        self._namespace = namespace 
     309 
     310        self._read , self._reader , self._write = None , None , None 
     311 
     312        self._incomingID = None 
     313        self._outgoingID = id 
     314 
     315        self._debug = _debug.Debug(debug,encoding=ENCODING) 
     316        self.DEBUG = self._debug.show # makes it backwards compatible with v0.4 code 
     317 
     318        self.DEBUG("stream init called",DBG_INIT) 
     319 
     320        if log: 
     321            if type(log) is type(""): 
     322                try: 
     323                    self._logFH = open(log,'w') 
     324                except: 
     325                    print "ERROR: can open %s for writing" % log 
     326                    sys.exit(0) 
     327            else: ## assume its a stream type object 
     328                self._logFH = log 
     329        else: 
     330            self._logFH = None 
     331        self._timestampLog = timestampLog 
     332 
     333    def connect(self): 
     334        NodeBuilder.__init__(self) 
     335        self._dispatch_depth = 2 
     336 
     337    def timestampLog(self,timestamp): 
     338        """ Enable or disable the showing of a timestamp in the log.