Back to index

nordugrid-arc-nox  1.1.0~rc6
client.py
Go to the documentation of this file.
00001 from arcom import get_child_nodes
00002 from arcom.client import Client
00003 from arcom.service import ahash_uri, librarian_uri, bartender_uri, rbyteio_uri, byteio_simple_uri, shepherd_uri, gateway_uri
00004 from arcom.service import true, false, parse_node, parse_to_dict, node_to_data, get_data_node
00005 
00006 from storage.common import parse_metadata, create_metadata
00007 
00008 from arcom.xmltree import XMLTree
00009 from xml.dom.minidom import parseString
00010 
00011 import threading
00012 import arc
00013 import base64
00014 import time
00015 import sys
00016 import socket
00017 
00018 class ISISClient(Client):
00019 
00020     def __init__(self, url, print_xml = False, ssl_config = {}):
00021         ns = self.NS_class('isis', 'http://www.nordugrid.org/schemas/isis/2007/06')
00022         Client.__init__(self, url, ns, print_xml, ssl_config = ssl_config)
00023 
00024     def getServiceURLs(self, service_type):
00025         query = XMLTree(from_tree =
00026             ('Query', [
00027                 ('QueryString', "/RegEntry/SrcAdv[Type = '%s']" % service_type)
00028             ])
00029         )
00030         QueryResponse = self.call(query, True)
00031         return QueryResponse.get_values('/QueryResponse/RegEntry/SrcAdv/EPR/Address')
00032 
00033 class AHashClient(Client):
00034 
00035     def __init__(self, url, print_xml = False, ssl_config = {}):
00036         ns = self.NS_class('ahash', ahash_uri)
00037         Client.__init__(self, url, ns, print_xml, ssl_config = ssl_config)
00038 
00039     def get_tree(self, IDs, neededMetadata = []):
00040         tree = XMLTree(from_tree =
00041             ('ahash:get', [
00042                 ('ahash:neededMetadataList', [
00043                     ('ahash:neededMetadataElement', [
00044                         ('ahash:section', section),
00045                         ('ahash:property', property)
00046                     ]) for section, property in neededMetadata
00047                 ]),
00048                 ('ahash:IDs', [
00049                     ('ahash:ID', i) for i in IDs
00050                 ])
00051             ])
00052         )
00053         msg = self.call(tree)
00054         xml = self.xmlnode_class(msg)
00055         error = str(xml.Get('Body').Child().Get('error'))
00056         if error:
00057             raise Exception, error
00058         ahash_prefix = xml.NamespacePrefix(ahash_uri)
00059         rewrite = {
00060             ahash_prefix + ':objects' : 'lbr:getResponseList',
00061             ahash_prefix + ':object' : 'lbr:getResponseElement',
00062             ahash_prefix + ':ID' : 'lbr:GUID',
00063             ahash_prefix + ':metadataList' : 'lbr:metadataList',
00064             ahash_prefix + ':metadata' : 'lbr:metadata',
00065             ahash_prefix + ':section' : 'lbr:section',
00066             ahash_prefix + ':property' : 'lbr:property',
00067             ahash_prefix + ':value' : 'lbr:value'
00068         }
00069         return XMLTree(get_data_node(xml), rewrite = rewrite)
00070 
00071     def get(self, IDs, neededMetadata = []):
00072         tree = XMLTree(from_tree =
00073             ('ahash:get', [
00074                 ('ahash:neededMetadataList', [
00075                     ('ahash:neededMetadataElement', [
00076                         ('ahash:section', section),
00077                         ('ahash:property', property)
00078                     ]) for section, property in neededMetadata
00079                 ]),
00080                 ('ahash:IDs', [
00081                     ('ahash:ID', i) for i in IDs
00082                 ])
00083             ])
00084         )
00085         msg = self.call(tree)
00086         xml = self.xmlnode_class(msg)
00087         error = str(xml.Get('Body').Child().Get('error'))
00088         if error:
00089             raise Exception, error
00090         objects = parse_node(get_data_node(xml), ['ID', 'metadataList'], single = True, string = False)
00091         return dict([(str(ID), parse_metadata(metadataList)) for ID, metadataList in objects.items()])
00092 
00093     def change(self, changes):
00094         """ Call the change method of the A-Hash service.
00095         
00096         change(changes)
00097 
00098         'changes' is a dictionary of {changeID : (ID, changeType, section, property, value, conditions)}
00099             where 'conditions' is a dictionary of {conditionID : (conditionType, section, property, value)}
00100         """
00101         
00102         tree = XMLTree(from_tree =
00103             ('ahash:change', [
00104                 ('ahash:changeRequestList', [
00105                     ('ahash:changeRequestElement', [
00106                         ('ahash:changeID', changeID),
00107                         ('ahash:ID', ID),
00108                         ('ahash:changeType', changeType),
00109                         ('ahash:section', section),
00110                         ('ahash:property', property),
00111                         ('ahash:value', value),
00112                         ('ahash:conditionList', [
00113                             ('ahash:condition', [
00114                                 ('ahash:conditionID', conditionID),
00115                                 ('ahash:conditionType',conditionType),
00116                                 ('ahash:section',conditionSection),
00117                                 ('ahash:property',conditionProperty),
00118                                 ('ahash:value',conditionValue)
00119                             ]) for conditionID, (conditionType, conditionSection,
00120                                         conditionProperty, conditionValue) in conditions.items()
00121                         ])
00122                     ]) for changeID, (ID, changeType, section, property, value, conditions) in changes.items()
00123                 ])
00124             ])
00125         )
00126         self.semapool.acquire()
00127         msg = self.call(tree)
00128         self.semapool.release()
00129         xml = self.xmlnode_class(msg)
00130         return parse_node(get_data_node(xml), ['changeID', 'success', 'conditionID'])
00131 
00132 class LibrarianClient(Client):
00133     
00134     def __init__(self, url, print_xml = False, ssl_config = {}):
00135         ns = self.NS_class('lbr', librarian_uri)
00136         Client.__init__(self, url, ns, print_xml, ssl_config = ssl_config)
00137 
00138     def get(self, GUIDs, neededMetadata = []):
00139         tree = XMLTree(from_tree =
00140             ('lbr:get', [
00141                 ('lbr:neededMetadataList', [
00142                     ('lbr:neededMetadataElement', [
00143                         ('lbr:section', section),
00144                         ('lbr:property', property)
00145                     ]) for section, property in neededMetadata
00146                 ]),
00147                 ('lbr:getRequestList', [
00148                     ('lbr:getRequestElement', [
00149                         ('lbr:GUID', i)
00150                     ]) for i in GUIDs
00151                 ])
00152             ])
00153         )
00154         msg = self.call(tree)
00155         xml = self.xmlnode_class(msg)
00156         elements = parse_node(get_data_node(xml),
00157             ['GUID', 'metadataList'], single = True, string = False)
00158         return dict([(str(GUID), parse_metadata(metadataList))
00159             for GUID, metadataList in elements.items()])
00160 
00161     def traverseLN(self, requests):
00162         tree = XMLTree(from_tree =
00163             ('lbr:traverseLN', [
00164                 ('lbr:traverseLNRequestList', [
00165                     ('lbr:traverseLNRequestElement', [
00166                         ('lbr:requestID', rID),
00167                         ('lbr:LN', LN)
00168                     ]) for rID, LN in requests.items()
00169                 ])
00170             ])
00171         )
00172         msg = self.call(tree)
00173         xml = self.xmlnode_class(msg)
00174         list_node = get_data_node(xml)
00175         list_number = list_node.Size()
00176         elements = {}
00177         for i in range(list_number):
00178             element_node = list_node.Child(i)
00179             requestID = str(element_node.Get('requestID'))
00180             traversedlist_node = element_node.Get('traversedList')
00181             traversedlist_number = traversedlist_node.Size()
00182             traversedlist = []
00183             for j in range(traversedlist_number):
00184                 tle_node = traversedlist_node.Child(j)
00185                 traversedlist.append((str(tle_node.Get('LNPart')), str(tle_node.Get('GUID'))))
00186             wasComplete = str(element_node.Get('wasComplete')) == true
00187             traversedLN = str(element_node.Get('traversedLN'))
00188             restLN = str(element_node.Get('restLN'))
00189             GUID = str(element_node.Get('GUID'))
00190             metadatalist_node = element_node.Get('metadataList')
00191             metadata = parse_metadata(metadatalist_node)
00192             elements[requestID] = (metadata, GUID, traversedLN, restLN, wasComplete, traversedlist)
00193         return elements
00194 
00195     def new(self, requests):
00196         
00197         tree = XMLTree(from_tree =
00198             ('lbr:new', [
00199                 ('lbr:newRequestList', [
00200                     ('lbr:newRequestElement', [
00201                         ('lbr:requestID', requestID),
00202                         ('lbr:metadataList', create_metadata(metadata, 'lbr'))
00203                     ]) for requestID, metadata in requests.items()
00204                 ])
00205             ])
00206         )
00207         self.semapool.acquire()
00208         response = self.call(tree)
00209         self.semapool.release()
00210         node = self.xmlnode_class(response)
00211         return parse_node(get_data_node(node), ['requestID', 'GUID', 'success'])
00212 
00213     def modifyMetadata(self, requests):
00214         tree = XMLTree(from_tree =
00215             ('lbr:modifyMetadata', [
00216                 ('lbr:modifyMetadataRequestList', [
00217                     ('lbr:modifyMetadataRequestElement', [
00218                         ('lbr:changeID', changeID),
00219                         ('lbr:GUID', GUID),
00220                         ('lbr:changeType', changeType),
00221                         ('lbr:section', section),
00222                         ('lbr:property', property),
00223                         ('lbr:value', value)
00224                     ]) for changeID, (GUID, changeType, section, property, value) in requests.items()
00225                 ])
00226             ])
00227         )
00228         self.semapool.acquire()
00229         response = self.call(tree)
00230         self.semapool.release()
00231         node = self.xmlnode_class(response)
00232         return parse_node(get_data_node(node), ['changeID', 'success'], True)
00233 
00234     def remove(self, requests):
00235         tree = XMLTree(from_tree =
00236             ('lbr:remove', [
00237                 ('lbr:removeRequestList', [
00238                     ('lbr:removeRequestElement', [
00239                         ('lbr:requestID', requestID),
00240                         ('lbr:GUID', GUID)
00241                     ]) for requestID, GUID in requests.items()
00242                 ])
00243             ])
00244         )
00245         self.semapool.acquire()
00246         response = self.call(tree)
00247         self.semapool.release()
00248         node = self.xmlnode_class(response)
00249         return parse_node(get_data_node(node), ['requestID', 'success'], True)
00250 
00251     def report(self, serviceID, filelist):
00252         tree = XMLTree(from_tree =
00253             ('lbr:report', [
00254                 ('lbr:serviceID', serviceID),
00255                 ('lbr:filelist', [
00256                     ('lbr:file', [
00257                         ('lbr:GUID', GUID),
00258                         ('lbr:referenceID', referenceID),
00259                         ('lbr:state', state)
00260                     ]) for GUID, referenceID, state in filelist
00261                 ])
00262             ])
00263         )
00264         response = self.call(tree)
00265         node = self.xmlnode_class(response)
00266         try:
00267             return int(str(node.Child().Child().Get('nextReportTime')))
00268         except:
00269             return None
00270 
00271 class BartenderClient(Client):
00272     """ Client for the Bartender service. """
00273     
00274     def __init__(self, url, print_xml = False, ssl_config = {}):
00275         """ Constructior of the client.
00276         
00277         BartenderClient(url, print_xml = False)
00278         
00279         url is the URL of the Bartender service
00280         if print_xml is true this will print the SOAP messages
00281         """
00282         # sets the namespace
00283         ns = self.NS_class('bar', bartender_uri)
00284         # calls the superclass' constructor
00285         Client.__init__(self, url, ns, print_xml, ssl_config = ssl_config)
00286 
00287     def stat(self, requests):
00288         """ Get metadata of a file or collection
00289         
00290         stat(requests)
00291         
00292         requests is a dictionary where requestIDs are the keys, and Logical Names are the values.
00293         this method returns a dictionary for each requestID which contains all the metadata with (section, dictionary) as the key
00294         
00295         e.g.
00296         
00297         In: {'frodo':'/', 'sam':'/testfile'}
00298         Out:
00299  
00300             {'frodo': {('entry', 'type'): 'collection',
00301                        ('entries', 'testdir'): '4cabc8cb-599d-488c-a253-165f71d4e180',
00302                        ('entries', 'testfile'): 'cf05727b-73f3-4318-8454-16eaf10f302c',
00303                        ('states', 'closed'): '0'},
00304              'sam': {('entry', 'type'): 'file',
00305                      ('locations', 'http://localhost:60000/Shepherd 00d6388c-42df-441c-8d9f-bd78c2c51667'): 'alive',
00306                      ('locations', 'http://localhost:60000/Shepherd 51c9b49a-1472-4389-90d2-0f18b960fe29'): 'alive',
00307                      ('states', 'checksum'): '0927c28a393e8834aa7b838ad8a69400',
00308                      ('states', 'checksumType'): 'md5',
00309                      ('states', 'neededReplicas'): '5',
00310                      ('states', 'size'): '11'}}
00311         """
00312         tree = XMLTree(from_tree =
00313             ('bar:stat', [
00314                 ('bar:statRequestList', [
00315                     ('bar:statRequestElement', [
00316                         ('bar:requestID', requestID),
00317                         ('bar:LN', LN) 
00318                     ]) for requestID, LN in requests.items()
00319                 ])
00320             ])
00321         )
00322         msg = self.call(tree)
00323         xml = self.xmlnode_class(msg)
00324         elements = parse_node(get_data_node(xml),
00325             ['requestID', 'metadataList'], single = True, string = False)
00326         return dict([(str(requestID), parse_metadata(metadataList))
00327             for requestID, metadataList in elements.items()])
00328 
00329     def getFile(self, requests):
00330         """ Initiate download of a file.
00331         
00332         getFile(requests)
00333         
00334         requests is a dicitonary with requestID as key and (LN, protocols) as value,
00335             where LN is the Logical Name
00336             protocols is a list of strings: the supported transfer protocols by the client
00337         returns a dictionary with requestID as key and [success, TURL, protocol] as value, where
00338             success is the status of the request
00339             TURL is the Transfer URL
00340             protocol is the name of the choosen protocol
00341             
00342         Example:
00343         In: {'1':['/', ['byteio']], 'a':['/testfile', ['ftp', 'byteio']]}
00344         Out: 
00345             {'1': ['is not a file', '', ''],
00346              'a': ['done',
00347                    'http://localhost:60000/byteio/29563f36-e9cb-47eb-8186-0d720adcbfca',
00348                    'byteio']}
00349         """
00350         tree = XMLTree(from_tree =
00351             ('bar:getFile', [
00352                 ('bar:getFileRequestList', [
00353                     ('bar:getFileRequestElement', [
00354                         ('bar:requestID', rID),
00355                         ('bar:LN', LN)
00356                     ] + [
00357                         ('bar:protocol', protocol) for protocol in protocols
00358                     ]) for rID, (LN, protocols) in requests.items()
00359                 ])
00360             ])
00361         )
00362         msg = self.call(tree)
00363         xml = self.xmlnode_class(msg)
00364         return parse_node(get_data_node(xml), ['requestID', 'success', 'TURL', 'protocol'])
00365     
00366     def putFile(self, requests):
00367         """ Initiate uploading a file.
00368         
00369         putFile(requests)
00370         
00371         requests is a dictionary with requestID as key, and (LN, metadata, protocols) as value, where
00372             LN is the Logical Name
00373             metadata is a dictionary with (section,property) as key, it contains the metadata of the new file
00374             protocols is a list of protocols supported by the client
00375         returns a dictionary with requestID as key, and (success, TURL, protocol) as value, where
00376             success is the state of the request
00377             TURL is the transfer URL
00378             protocol is the name of the choosen protocol
00379             
00380         Example:
00381         In: {'qwe': ['/newfile',
00382                     {('states', 'size') : 1055, ('states', 'checksum') : 'none', ('states', 'checksumType') : 'none'},
00383                     ['byteio']]}
00384         Out: 
00385             {'qwe': ['done',
00386                      'http://localhost:60000/byteio/d42f0993-79a8-4bba-bd86-84324367c65f',
00387                      'byteio']}
00388         """
00389         tree = XMLTree(from_tree =
00390             ('bar:putFile', [
00391                 ('bar:putFileRequestList', [
00392                     ('bar:putFileRequestElement', [
00393                         ('bar:requestID', rID),
00394                         ('bar:LN', LN),
00395                         ('bar:metadataList', create_metadata(metadata, 'bar')),
00396                     ] + [
00397                         ('bar:protocol', protocol) for protocol in protocols
00398                     ]) for rID, (LN, metadata, protocols) in requests.items()
00399                 ])
00400             ])
00401         )
00402         self.semapool.acquire()
00403         msg = self.call(tree)
00404         self.semapool.release()
00405         xml = self.xmlnode_class(msg)
00406         return parse_node(get_data_node(xml), ['requestID', 'success', 'TURL', 'protocol'])
00407 
00408     def delFile(self, requests):
00409         """ Initiate deleting a file.
00410         
00411         delFile(requests)
00412         
00413         requests is a dictionary with requestID as key, and (LN) as value, where
00414         LN is the Logical Name of the file to be deleted
00415         
00416         returns a dictionary with requestID as key, and (success) as value,
00417         where success is the state of the request 
00418         (one of 'deleted', 'noSuchLN', 'denied)
00419 
00420         Example:
00421         In: {'fish': ['/cod']}
00422         Out: {'fish': ['deleted']}
00423         """
00424         tree = XMLTree(from_tree =
00425             ('bar:delFile', [
00426                 ('bar:delFileRequestList', [
00427                     ('bar:delFileRequestElement', [
00428                         ('bar:requestID', requestID),
00429                         ('bar:LN', LN) 
00430                     ]) for requestID, LN in requests.items()
00431                 ])
00432             ])
00433         )
00434         self.semapool.acquire()
00435         msg = self.call(tree)
00436         self.semapool.release()
00437         xml = self.xmlnode_class(msg)
00438         return parse_node(get_data_node(xml), ['requestID', 'success'], single = True)
00439 
00440 
00441     def addReplica(self, requests, protocols):
00442         """ Add a new replica to an existing file.
00443         
00444         addReplica(requests, protocols)
00445         
00446         requests is a dictionary with requestID as key and GUID as value.
00447         protocols is a list of protocols supported by the client
00448         
00449         returns a dictionary with requestID as key and (success, TURL, protocol) as value, where
00450             success is the status of the request,
00451             TURL is the transfer URL
00452             protocol is the choosen protocol
00453             
00454         Example:
00455         
00456         In: requests = {'001':'c9c82371-4773-41e4-aef3-caf7c7eaf6f8'}, protocols = ['http','byteio']
00457         Out:
00458             {'001': ['done',
00459                      'http://localhost:60000/byteio/c94a77a1-347c-430c-ae1b-02d83786fb2d',
00460                     'byteio']}
00461         """
00462         tree = XMLTree(from_tree =
00463             ('bar:addReplica', [
00464                 ('bar:addReplicaRequestList', [
00465                     ('bar:putReplicaRequestElement', [
00466                         ('bar:requestID', rID),
00467                         ('bar:GUID', GUID),
00468                     ]) for rID, GUID in requests.items()
00469                 ])
00470             ] + [
00471                 ('bar:protocol', protocol) for protocol in protocols
00472             ])
00473         )
00474         self.semapool.acquire()
00475         msg = self.call(tree)
00476         self.semapool.release()
00477         xml = self.xmlnode_class(msg)
00478         return parse_node(get_data_node(xml), ['requestID', 'success', 'TURL', 'protocol'])
00479 
00480     def unlink(self, requests):
00481         """docstring for unlink"""
00482         tree = XMLTree(from_tree =
00483             ('bar:unlink', [
00484                 ('bar:unlinkRequestList', [
00485                     ('bar:unlinkRequestElement', [
00486                         ('bar:requestID', rID),
00487                         ('bar:LN', LN),
00488                     ]) for rID, LN in requests.items()
00489                 ])
00490             ])
00491         )
00492         self.semapool.acquire()
00493         msg = self.call(tree)
00494         self.semapool.release()
00495         xml = self.xmlnode_class(msg)
00496         return parse_node(get_data_node(xml), ['requestID', 'success'], single = True)
00497     
00498 
00499     def unmakeCollection(self, requests):
00500         """docstring for unmakeCollection"""
00501         tree = XMLTree(from_tree =
00502             ('bar:unmakeCollection', [
00503                 ('bar:unmakeCollectionRequestList', [
00504                     ('bar:unmakeCollectionRequestElement', [
00505                         ('bar:requestID', rID),
00506                         ('bar:LN', LN),
00507                     ]) for rID, LN in requests.items()
00508                 ])
00509             ])
00510         )
00511         self.semapool.acquire()
00512         msg = self.call(tree)
00513         self.semapool.release()
00514         xml = self.xmlnode_class(msg)
00515         return parse_node(get_data_node(xml), ['requestID', 'success'], single = True)
00516 
00517     def makeCollection(self, requests):
00518         """ Create a new collection.
00519         
00520         makeCollection(requests)
00521 
00522         requests is a dictionary with requestID as key and (LN, metadata) as value, where
00523             LN is the Logical Name
00524             metadata is the metadata of the new collection, a dictionary with (section, property) as key
00525         returns a dictionary with requestID as key and the state of the request as value
00526         
00527         In: {'b5':['/coloredcollection', {('metadata','color') : 'light blue'}]}
00528         Out: {'b5': 'done'}
00529         """
00530         tree = XMLTree(from_tree =
00531             ('bar:makeCollection', [
00532                 ('bar:makeCollectionRequestList', [
00533                     ('bar:makeCollectionRequestElement', [
00534                         ('bar:requestID', rID),
00535                         ('bar:LN', LN),
00536                         ('bar:metadataList', create_metadata(metadata, 'bar'))
00537                     ]) for rID, (LN, metadata) in requests.items()
00538                 ])
00539             ])
00540         )
00541         self.semapool.acquire()
00542         msg = self.call(tree)
00543         self.semapool.release()
00544         xml = self.xmlnode_class(msg)
00545         return parse_node(get_data_node(xml), ['requestID', 'success'], single = True)
00546 
00547     ### Created by Salman Toor ###
00548     def makeMountpoint(self, requests):
00549         """ Create a new Mountpoint.
00550         
00551         makeMountpoint(requests)
00552 
00553         requests is a dictionary with requestID as key and (LN, metadata) as value, where
00554             LN is the Logical Name
00555             metadata is the metadata of the new collection, a dictionary with (section, property) as key
00556         returns a dictionary with requestID as key and the state of the request as value
00557         
00558         In: {'b5':['/coloredcollection', {('metadata','color') : 'light blue'}]}
00559         Out: {'b5': 'done'}
00560         """
00561         tree = XMLTree(from_tree =
00562             ('bar:makeMountpoint', [
00563                 ('bar:makeMountpointRequestList', [
00564                     ('bar:makeMountpointRequestElement', [
00565                         ('bar:requestID', rID),
00566                         ('bar:LN', LN),
00567                         ('bar:URL', URL),
00568                         ('bar:metadataList', create_metadata(metadata, 'bar'))
00569                     ]) for rID, (LN,metadata,URL) in requests.items()
00570                 ])
00571             ])
00572         )
00573 
00574         self.semapool.acquire()
00575         msg = self.call(tree)
00576         self.semapool.release()
00577         xml = self.xmlnode_class(msg)
00578         return parse_node(get_data_node(xml), ['requestID', 'success'], single = True)
00579         
00580     def unmakeMountpoint(self, requests):
00581         """docstring for unmakeMountpoint"""
00582         tree = XMLTree(from_tree =
00583             ('bar:unmakeMountpoint', [
00584                 ('bar:unmakeMountpointRequestList', [
00585                     ('bar:unmakeMountpointRequestElement', [
00586                         ('bar:requestID', rID),
00587                         ('bar:LN', LN),
00588                     ]) for rID, LN in requests.items()
00589                 ])
00590             ])
00591         )
00592         self.semapool.acquire()
00593         msg = self.call(tree)
00594         self.semapool.release()
00595         xml = self.xmlnode_class(msg)
00596         return parse_node(get_data_node(xml), ['requestID', 'success'], single = True)
00597         ###    ###
00598 
00599     def list(self, requests, neededMetadata = []):
00600         """ List the contents of a collection.
00601         
00602         list(requests, neededMetadata = [])
00603         
00604         requests is a dictionary with requestID as key and Logical Name as value
00605         neededMetadata is a list of (section, property) pairs
00606             if neededMetadata is empty, list will return all metadata for each collection-entry
00607             otherwise just those values will be returnd which has a listed (section, property)
00608             if a property is empty means that all properties will be listed from that section
00609         returns a dictionary with requestID as key and (entries, status) as value, where
00610             entries is a dictionary with the entry name as key and (GUID, metadata) as value
00611             status is the status of the request
00612         
00613         Example:
00614         In: requests = {'jim': '/', 'kirk' : '/testfile'}, neededMetadata = [('states','size'),('entry','type')]
00615         Out: 
00616             {'jim': ({'coloredcollection': ('cab8d235-4afa-4e33-a85f-fde47b0240d1', {('entry', 'type'): 'collection'}),
00617                       'newdir': ('3b200a34-0d63-4d15-9b01-3693685928bc', {('entry', 'type'): 'collection'}),
00618                       'newfile': ('c9c82371-4773-41e4-aef3-caf7c7eaf6f8', {('entry', 'type'): 'file', ('states', 'size'): '1055'}),
00619                       'testdir': ('4cabc8cb-599d-488c-a253-165f71d4e180', {('entry', 'type'): 'collection'}),
00620                       'testfile': ('cf05727b-73f3-4318-8454-16eaf10f302c', {('entry', 'type'): 'file', ('states', 'size'): '11'})},
00621                      'found'),
00622              'kirk': ({}, 'is a file')}
00623         """
00624 
00625         if requests['0'] == "-deleg":
00626             delegID = self.delegateCredentials()
00627             #print delegID
00628             if delegID == 0:
00629                 return "cannot delegate Credentials, check the Env. variables"
00630             del requests['0']
00631 
00632         tree = XMLTree(from_tree =
00633             ('bar:list', [
00634                 ('bar:listRequestList', [
00635                     ('bar:listRequestElement', [
00636                         ('bar:requestID', requestID),
00637                         ('bar:LN', LN)
00638                     ]) for requestID, LN in requests.items()
00639                 ]),
00640                 ('bar:neededMetadataList', [
00641                     ('bar:neededMetadataElement', [
00642                         ('bar:section', section),
00643                         ('bar:property', property)
00644                     ]) for section, property in neededMetadata
00645                 ])
00646             ])
00647         )
00648         msg = self.call(tree)
00649         xml = self.xmlnode_class(msg)
00650         elements = parse_node(get_data_node(xml),
00651             ['requestID', 'entries', 'status'], string = False)
00652         return dict([
00653             (   str(requestID), 
00654                 (dict([(str(name), (str(GUID), parse_metadata(metadataList))) for name, (GUID, metadataList) in
00655                     parse_node(entries, ['name', 'GUID', 'metadataList'], string = False).items()]),
00656                 str(status))
00657             ) for requestID, (entries, status) in elements.items()
00658         ])
00659 
00660     def move(self, requests):
00661         """ Move a file or collection within the global namespace.
00662         
00663         move(requests)
00664         
00665         requests is a dictionary with requestID as key, and (sourceLN, targetLN, preserveOriginal) as value, where
00666             sourceLN is the source Logical Name
00667             targetLN is the target Logical Name
00668             preserverOriginal is True if we want to create a hardlink
00669         returns a dictionary with requestID as key and status as value
00670         
00671         Example:
00672         In: {'shoo':['/testfile','/newname',False]}
00673         Out: {'shoo': ['moved']}
00674         """
00675         tree = XMLTree(from_tree =
00676             ('bar:move', [
00677                 ('bar:moveRequestList', [
00678                     ('bar:moveRequestElement', [
00679                         ('bar:requestID', requestID),
00680                         ('bar:sourceLN', sourceLN),
00681                         ('bar:targetLN', targetLN),
00682                         ('bar:preserveOriginal', preserveOriginal and true or false)
00683                     ]) for requestID, (sourceLN, targetLN, preserveOriginal) in requests.items()
00684                 ])
00685             ])
00686         )
00687         self.semapool.acquire()
00688         msg = self.call(tree)
00689         self.semapool.release()
00690         xml = self.xmlnode_class(msg)
00691         return parse_node(get_data_node(xml), ['requestID', 'status'], single = False)
00692 
00693     def modify(self, requests):
00694         tree = XMLTree(from_tree =
00695             ('bar:modify', [
00696                 ('bar:modifyRequestList', [
00697                     ('bar:modifyRequestElement', [
00698                         ('bar:changeID', changeID),
00699                         ('bar:LN', LN),
00700                         ('bar:changeType', changeType),
00701                         ('bar:section', section),
00702                         ('bar:property', property),
00703                         ('bar:value', value)
00704                     ]) for changeID, (LN, changeType, section, property, value) in requests.items()
00705                 ])
00706             ])
00707         )
00708         self.semapool.acquire()
00709         response = self.call(tree)
00710         self.semapool.release()
00711         node = self.xmlnode_class(response)
00712         return parse_node(get_data_node(node), ['changeID', 'success'], True)
00713 
00714 class ShepherdClient(Client):
00715 
00716     def __init__(self, url, print_xml = False, ssl_config = {}):
00717         ns = self.NS_class('she', shepherd_uri)
00718         Client.__init__(self, url, ns, print_xml, ssl_config = ssl_config)
00719 
00720     def _putget(self, putget, requests):
00721         tree = XMLTree(from_tree =
00722             ('she:' + putget, [
00723                 ('she:' + putget + 'RequestList', [
00724                     ('she:' + putget + 'RequestElement', [
00725                         ('she:requestID', requestID),
00726                         ('she:' + putget + 'RequestDataList', [
00727                             ('she:' + putget + 'RequestDataElement', [
00728                                 ('she:property', property),
00729                                 ('she:value', value)
00730                             ]) for property, value in requestData
00731                         ])
00732                     ]) for requestID, requestData in requests.items()
00733                 ])
00734             ])
00735         )
00736         msg = self.call(tree)
00737         xml = self.xmlnode_class(msg)
00738         try:
00739             response = dict([
00740                 (str(node.Get('requestID')), [
00741                     (str(n.Get('property')), str(n.Get('value')))
00742                         for n in get_child_nodes(node.Get(putget + 'ResponseDataList'))
00743                 ]) for node in get_child_nodes(get_data_node(xml))])
00744             return response
00745         except:
00746             raise Exception, msg
00747 
00748     def put(self, requests):
00749         self.semapool.acquire()
00750         res = self._putget('put', requests)
00751         self.semapool.release()
00752         return res
00753 
00754     def get(self, requests):
00755         return self._putget('get', requests)
00756 
00757     def delete(self, requests):
00758         tree = XMLTree(from_tree =
00759             ('she:delete', [
00760                 ('she:deleteRequestList', [
00761                     ('she:deleteRequestElement', [
00762                         ('she:requestID', requestID),
00763                         ('she:referenceID', referenceID)
00764                     ]) for requestID, referenceID in requests.items()
00765                 ])
00766             ])
00767         )
00768         self.semapool.acquire()
00769         msg = self.call(tree)
00770         self.semapool.release()
00771         xml = self.xmlnode_class(msg)
00772         return parse_node(get_data_node(xml), ['requestID', 'status'])
00773         
00774 
00775     def stat(self, requests):
00776         tree = XMLTree(from_tree =
00777             ('she:stat', [
00778                 ('she:statRequestList', [
00779                     ('she:statRequestElement', [
00780                         ('she:requestID', requestID),
00781                         ('she:referenceID', referenceID)
00782                     ]) for requestID, referenceID in requests.items()
00783                 ])
00784             ])
00785         )
00786         msg = self.call(tree)
00787         xml = self.xmlnode_class(msg)
00788         return parse_to_dict(get_data_node(xml),
00789             ['requestID', 'referenceID', 'state', 'checksumType', 'checksum', 'acl', 'size', 'GUID', 'localID'])
00790 
00791     def toggleReport(self, doReporting):
00792         tree = XMLTree(from_tree =
00793             ('she:toggleReport', [
00794                 ('she:doReporting', doReporting and true or false)
00795             ])
00796         )
00797         return self.call(tree, True)
00798 
00799 class NotifyClient(Client):
00800 
00801     def __init__(self, url, print_xml = False, ssl_config = {}):
00802         ns = self.NS_class('she', shepherd_uri)
00803         Client.__init__(self, url, ns, print_xml, ssl_config = ssl_config)
00804 
00805     def notify(self, subject, state):
00806         tree = XMLTree(from_tree =
00807             ('she:notify', [
00808                 ('she:subject', subject),
00809                 ('she:state', state)
00810             ])
00811         )
00812         msg = self.call(tree)
00813         return msg
00814 
00815 class ByteIOClient(Client):
00816 
00817     def __init__(self, url, print_xml = False, ssl_config = {}):
00818         ns = self.NS_class('rb', rbyteio_uri)
00819         Client.__init__(self, url, ns, print_xml, ssl_config = ssl_config)
00820 
00821     def read(self, start_offset = None, bytes_per_block = None, num_blocks = None, stride = None, file = None):
00822         request = []
00823         if start_offset is not None:
00824             request.append(('rb:start-offset', start_offset))
00825         if bytes_per_block is not None:
00826             request.append(('rb:bytes-per-block', bytes_per_block))
00827         if num_blocks is not None:
00828             request.append(('rb:num-blocks', num_blocks))
00829         if stride is not None:
00830             request.append(('rb:stride', stride))
00831         tree = XMLTree(from_tree = ('rb:read', request))
00832         msg = self.call(tree)
00833         xml = self.xmlnode_class(msg)
00834         data_encoded = str(xml.Child().Child().Get('transfer-information'))
00835         if file:
00836             file.write(base64.b64decode(data_encoded))
00837             file.close()
00838         else:
00839             return base64.b64decode(data_encoded)
00840 
00841     def write(self, data, start_offset = None, bytes_per_block = None, stride = None):
00842         if isinstance(data,file):
00843             data = data.read()
00844         out = arc.PayloadSOAP(self.ns)
00845         request_node = out.NewChild('rb:write')
00846         if start_offset is not None:
00847             request_node.NewChild('rb:start-offset').Set(str(start_offset))
00848         if bytes_per_block is not None:
00849             request_node.NewChild('rb:bytes-per-block').Set(str(bytes_per_block))
00850         if stride is not None:
00851             request_node.NewChild('rb:stride').Set(str(stride))
00852         transfer_node = request_node.NewChild('rb:transfer-information')
00853         transfer_node.NewAttribute('transfer-mechanism').Set(byteio_simple_uri)
00854         encoded_data = base64.b64encode(data)
00855         transfer_node.Set(encoded_data)
00856         resp = self.call_raw(out)
00857         return resp