def __init__(self,params,queue): '''DataUpdater base initialiser. @param params: List of configuration parameters @type params: List<?> @param queue: Response queue @type queues: Queue.Queue ''' super(DataUpdater,self).__init__() self.ref,self.conf,self.factory = params self.queue = queue #self._stop = threading.Event() self.api = AimsApi(self.conf)
class DataUpdater(Observable): '''Mantenence thread comtrolling data updates and api interaction. Instantiates an amisapi instance with wrappers for initialisation of local data store and change/resolution feed updating ''' #et = FeatureType.ADDRESS #ft = FeedType.FEATURES address = None pno = 0 changeId = 0 global aimslog aimslog = Logger.setup() getfeat = None def __init__(self,params,queue): '''DataUpdater base initialiser. @param params: List of configuration parameters @type params: List<?> @param queue: Response queue @type queues: Queue.Queue ''' super(DataUpdater,self).__init__() self.ref,self.conf,self.factory = params self.queue = queue #self._stop = threading.Event() self.api = AimsApi(self.conf) def setup(self,etft,sw,ne,pno): '''Parameter setup. @param etft: Feed/Feature identifier @type etft: FeedRef @param sw: South-West corner, coordinate value pair @type sw: List<Double>{2} @param ne: North-East corner, coordinate value pair @type ne: List<Double>{2} @param pno: Feed page number @type pno: Integer ''' self.etft = etft self.sw,self.ne = sw,ne self.pno = pno def run(self): '''Main updater run method fetching single page of addresses from API''' aimslog.info('GET.{} {} - Page{}'.format(self.ref,self.etft,self.pno)) featlist = [] #for page in self.api.getOnePage(self.etft,self.sw,self.ne,self.pno): # featlist.append(self.processPage(page,self.etft)) ce,pages = self.api.getOnePage(self.etft,self.sw,self.ne,self.pno) if any(ce.values()): aimslog.error('Single-page request failure {}'.format(ce)) if pages.has_key('entities'): for page in pages['entities']: featlist.append(self.processPage(page,self.etft)) else: aimslog.error('Single-page response missing entities') self.queue.put(featlist) self.notify(self.ref) def processPage(self,page,etft): '''Process an individual page. If page is resolution type optionally re-query at individual level @param page: Processed results from pno request @type page: Dict<?> @param etft: Feed/Feature identifier @type etft: FeedRef ''' if etft.ft == FeedType.RESOLUTIONFEED and ENABLE_ENTITY_EVALUATION: cid = self.cid(page) ce,feat = self.api.getOneFeature(etft,cid) if any(ce.values()): aimslog.error('Single-feature request failure {}'.format(ce)) if feat == {u'class': [u'error']}: #if the pno request returns the not-supposed-to-happen error, it gets special treatment aimslog.error('Invalid API response {}'.format(feat)) #return self.factory.get(model=pno['properties']) else: return self._processEntity(feat,cid,etft) else: #just return the main feedlevel address objects return self.factory.get(model=page['properties']) def _processEntity(self,feat,cid,etft): '''Identify and select group, address or entity processing for a reolutionfeed feature @param feat: dict representation of feature before object processing @type feat: Dict @param cid: Change ID or group change ID @type cid: Integer @param etft: Feed/Feature identifier @type etft: FeedRef @return: Instantiated feature object ''' if feat['class'][0] == 'validation': return self._processValidationEntity(feat) #e = EntityValidation.getInstance(feat)# self.getEntityInstance() #------------------------------- # Resolution Group elif feat['class'][0] == 'resolutiongroup': return self._processResolutionGroup(feat,cid,etft) # Address List elif feat['class'][0] == 'addressresolution': return self._processAddressResolution(feat) #-------------------------------- # Simple Entity object else: return self._processSimpleEntity(self.factory.get,feat) def _processValidationEntity(self,feat): '''Wraps call to validation entity instantiator @param feat: dict representation of feature before object processing @type feat: Dict @return: Instantiated validation Entity ''' return EntityValidation.getInstance(feat) def _processAddressEntity(self,feat): '''Processes feature data into address object @param feat: dict representation of feature before object processing @type feat: Dict @return: Instantiated Address entity ''' #return EntityAddress.getInstance(feat) return self._processSimpleEntity(FeatureFactory.getInstance(FeedRef((FeatureType.ADDRESS,FeedType.RESOLUTIONFEED))).get,feat) def _processSimpleEntity(self,fact,feat): '''Default processor for generic entities but the same as address resolution processor (below). @param fact: Link to factory, object instantiation method @type fact: <Function> @param feat: dict representation of feature before object processing @type feat: Dict @return: Instantiated Address entity ''' featurelist = [] a = fact(model=feat['properties']) if feat.has_key('entities'): for e in feat['entities']: featurelist.append(self._populateEntity(e)) a._setEntities(featurelist) return a def _processAddressResolution(self,feat): '''Processes entries in the addressresolution entities list @param feat: dict representation of feature before object processing @type feat: Dict @return: Instantiated Address entity ''' featurelist = [] a = self.factory.get(model=feat['properties']) for e in feat['entities']: featurelist.append(self._populateEntity(e)) a._setEntities(featurelist) return a def _processResolutionGroup(self,feat,cid,etft): '''Processes the res-address objects in a res-group. Subsequently populates the sub entities as feature-addresses. @param feat: dict representation of feature before object processing @type feat: Dict @param cid: Change ID or group change ID @type cid: Integer @param etft: Feed/Feature identifier @type etft: FeedRef @return: Instantiated feature object ''' featurelist = [] g = self.factory.get(model=feat['properties'])#group #HACK subst cid for cid+count string ce,feat2 = self.api.getOneFeature(etft,'{}/address?count={}'.format(cid,MAX_FEATURE_COUNT))#group entity/adr list if any(ce.values()): aimslog.error('Single-feature request failure {}'.format(ce)) etft2 = FeedRef((FeatureType.ADDRESS,FeedType.RESOLUTIONFEED)) factory2 = FeatureFactory.getInstance(etft2) for f in feat2['entities']: a = factory2.get(model=f['properties']) elist2 = [] for e in f['entities']: elist2.append(self._populateEntity(e)) a._setEntities(elist2) featurelist.append(a) g._setEntities(featurelist) return g def _populateEntity(self,ent): '''Selects type and instantiates appropriate entity object. @param ent: dict representation of feature before object processing @type ent: Dict ''' if ent['class'][0] == 'validation': return self._processValidationEntity(ent) elif ent['class'][0] == 'address': ###res factory might work here instead #etft3 = FeedRef((FeatureType.ADDRESS,FeedType.FEATURES)) #factory3 = FeatureFactory.getInstance(etft3) #return factory3.get(model=e['properties']) return self._processAddressEntity(ent) else: return Entity.getInstance(ent) @staticmethod def getInstance(etft): '''Based on the provided FeedRef this getInstance returns a group,address or user updater object @param etft: Feed/Feature identifier @type etft: FeedRef ''' if etft.et == FeatureType.GROUPS: return DataUpdaterGroup elif etft.et == FeatureType.ADDRESS: return DataUpdaterAddress elif etft.et == FeatureType.USERS: return DataUpdaterUser else: raise DataUpdaterSelectionException('Select Address,Groups or Users') def stop(self): self._stop.set() def stopped(self): return self._stop.isSet() def close(self): aimslog.info('Queue {} stopped'.format(self.queue.qsize())) self.queue.task_done() #executed by subclass def cid(self,_): pass