def setResolution(self, resolution): duration = iso.parse_duration(resolution) self.resolution = int(duration.total_seconds()) if 'days' in dir(duration): self.resolution += int(duration.days) * 86400 if 'months' in dir(duration): self.resolution += int(duration.months) * 2592000
def setAcquisitionInterval(self, acquisition_interval): duration = iso.parse_duration(acquisition_interval) self.acquisition_interval = int(duration.total_seconds()) if 'days' in dir(duration): self.acquisition_interval += int(duration.days) * 86400 if 'months' in dir(duration): self.acquisition_interval += int(duration.months) * 2592000
def execute(args): dtconfig = False debug = False config = False header = 0 user = None if 'user' in args and args['user'] is not None: user = args['user'] password = None if 'password' in args and args['password'] is not None: password = args['password'] auth = None if user and password: auth = HTTPBasicAuth(user, password) if 'c' in args and args['c'] is not None: with open(args['c'], 'r') as f: config = json.loads(f.read()) url = config['url'] service = config['service'] procedure = config['procedure'] if "datetime" in config: dtconfig = config["datetime"] if "header" in config: header = config["header"] duration = None aggregationFunction = None if "aggregationInterval" in config: duration = iso.parse_duration(config['aggregationInterval']) aggregationFunction = [] s = serial.Serial(config['port'], config['baud']) else: url = args['u'] service = args['s'] procedure = args['p'] s = serial.Serial(args['x'], args['b']) s.timeout = 5 if 'v' in args: debug = args['v'] # Requesting service configuration info res = requests.get('%s/wa/istsos/services/%s/configsections' % (url, service), auth=auth) istConfig = res.json()['data'] defaultNaN = istConfig["getobservation"]["aggregatenodata"] # Requesting a describe sensor mainly to store the assignedSensorId res = requests.get('%s/wa/istsos/services/%s/procedures/%s' % (url, service, procedure), auth=auth) ds = res.json()['data'] if debug: print "Loading info: %s" % procedure # Preparing "io" object to send res = requests.get( '%s/wa/istsos/services/%s/operations/getobservation/offerings/' 'temporary/procedures/%s/observedproperties/:/eventtime/last' % (url, service, procedure), params={"qualityIndex": "False"}, auth=auth) io = { "AssignedSensorId": ds['assignedSensorId'], "ForceInsert": "true", "Observation": res.json()['data'][0] } ec = int(io['Observation']['result']['DataArray']['elementCount']) - 1 # If config file given, check observedproperties exactness observations = [] columns = [] nodata = [] aggregation = None for idx in range(1, len(io["Observation"]['result']['DataArray']['field'])): observation = io["Observation"]['result']['DataArray']['field'][idx] observations.append(observation['definition']) columns.append((idx - 1)) nodata.append(defaultNaN) if aggregationFunction is not None: aggregationFunction.append("") print aggregationFunction if config: for observation in config["observations"]: if observation['name'] not in observations: print "Warning: procedure \"%s\" does not observe %s" % ( procedure, observation['name']) s.close() exit() else: idx = observations.index(observation['name']) columns[idx] = int(observation['column']) if "nodata" in observation: nodata[idx] = str(observation['nodata']) if "aggregation" in observation: aggregationFunction[idx] = observation["aggregation"] skip = True sample = True line = 0 startDate = None while True: if skip: # clear buffer (avoid bad read) print "Wait for serial" s.flushInput() s.readline() time.sleep(1) skip = False continue elif line < header: print "Skipping line: %s " % line s.flushInput() time.sleep(1) line = line + 1 continue try: message = s.readline().strip() data = message.split(',') print data if dtconfig: if 'column' in dtconfig: eventtime = datetime.strptime( data[int(dtconfig['column'])], dtconfig['format']) elif 'date' in dtconfig and 'time' in dtconfig: d = datetime.strptime( data[int(dtconfig['date']['column'])], dtconfig['date']['format']) t = datetime.strptime( data[int(dtconfig['time']['column'])], dtconfig['time']['format']) eventtime = datetime.combine(d, t.time()) else: print "Warning: date time configuration wrong" s.close() exit() if "tz" in dtconfig: eventtime = getDateTimeWithTimeZone( eventtime, dtconfig["tz"]) else: eventtime = datetime.now(tzlocal()) if startDate is None: startDate = eventtime if aggregation is None: aggregation = [] for idx in range( 1, len(io["Observation"]['result']['DataArray'] ['field'])): aggregation.append([]) if aggregation and (startDate + duration) > eventtime: for idx in range(len(data)): aggregation[idx].append(float(data[idx])) else: if aggregation is not None: print "Preparing.." startDate = startDate + duration eventtime = startDate data = [] for idx in range(len(aggregation)): if aggregationFunction: if aggregationFunction[idx] == 'sum': data.append(str(sum(aggregation[idx]))) elif aggregationFunction[idx] == 'avg': data.append( str( sum(aggregation[idx]) / len(aggregation[idx]))) elif aggregationFunction[idx] == 'min': data.append(str(min(aggregation[idx]))) elif aggregationFunction[idx] == 'max': data.append(str(max(aggregation[idx]))) aggregation = None io["Observation"]['samplingTime'] = { "beginPosition": eventtime.isoformat(), "endPosition": eventtime.isoformat() } ob = [eventtime.isoformat()] for idx in range(len(columns)): column = columns[idx] if nodata[idx] == data[column]: ob.append(defaultNaN) else: ob.append(data[column]) io["Observation"]['result']['DataArray']['values'] = [ob] if sample: sample = False print "\nData sample:" for idx in range(len(observations)): print "%s = %s" % (observations[idx], data[columns[idx]]) print "\n" if debug: print "Sending data: %s" % (", ".join(ob)) res = requests.post( '%s/wa/istsos/services/%s/operations/insertobservation' % (url, service), data=json.dumps(io), auth=auth) line = line + 1 try: res.raise_for_status() if debug: print " > Insert Ok!" except requests.exceptions.HTTPError as ex: print "Error: inserting data.." s.close() exit() except Exception as rex: print traceback.print_exc() print "Error: inserting data:\n%s" % rex s.close()
def __init__(self, sosRequest, method, requestObject, sosConfig): f.sosFilter.__init__(self, sosRequest, method, requestObject, sosConfig) # @TODO Declare attribute first! # self.offering = None # etc.. #************************** if method == "GET": #---------- THE OFFERING if requestObject.has_key("offering"): self.offering = get_name_from_urn(requestObject["offering"], "offering", sosConfig) else: raise sosException.SOSException( 1, "Parameter \"offering\" is mandatory with multiplicity 1") #---------- THE OBSERVED PROPERTY if requestObject.has_key("observedProperty"): self.observedProperty = [] oprs = requestObject["observedProperty"].split(",") for opr in oprs: # get_name_from_urn limit the ability to ask for an observedProperty with LIKE: # eg: ask "water" to get all the water related data, "water:discharge", "water:temperature" ... #oprName = get_name_from_urn(opr,"property") oprName = opr self.observedProperty.append(oprName) # one-many ID else: raise sosException.SOSException( 1, "Parameter \"observedProperty\" is mandatory with multiplicity N" ) #---------- RESPONSE FORMAT if requestObject.has_key("responseFormat"): if not requestObject["responseFormat"] in sosConfig.parameters[ "GO_responseFormat"]: raise sosException.SOSException( 2, "Parameter \"responseFormat\" sent with invalid value : use one of %s" % "; ".join(sosConfig.parameters["GO_responseFormat"])) else: self.responseFormat = requestObject["responseFormat"] else: raise sosException.SOSException( 1, "Parameter \"responseFormat\" is mandatory with multiplicity 1" ) #one #OPTIONAL request parameters #---------- SRS FILTER if requestObject.has_key("srsName"): self.srsName = get_name_from_urn(requestObject["srsName"], "refsystem", sosConfig) if not self.srsName in sosConfig.parameters["GO_srs"]: raise sosException.SOSException( 2, "srsName \"%s\" not supported, use one of: %s" % (self.srsName, ",".join( sosConfig.parameters["GO_srs"]))) else: self.srsName = sosConfig.parameters["GO_srs"][0] #---------- TIME FILTER if requestObject.has_key('eventTime'): self.eventTime = [] for i in requestObject["eventTime"].replace(" ", "+").split(","): if len(i.split("/")) < 3: self.eventTime.append(i.split("/")) else: raise sosException.SOSException( 2, "Parameter \"eventTime\" bad formatted") tp = [] for t in self.eventTime: if len(t) == 2: tp.append(iso.parse_datetime(t[0])) tp.append(iso.parse_datetime(t[1])) if len(t) == 1: tp.append(iso.parse_datetime(t[0])) # Checking if some event limitation is reached #if sosConfig["maxGoPeriod"]: if int(sosConfig.maxGoPeriod) > 0: from datetime import timedelta d = timedelta(hours=int(sosConfig.maxGoPeriod)) userPeriod = max(tp) - min(tp) if d < userPeriod: raise sosException.SOSException( 2, "You are requesting data for a period of [%s hours], but you are not permitted to ask for a period longer than: %s hours" % (userPeriod, d)) else: self.eventTime = None #---------- PROCEDURES FILTER if requestObject.has_key("procedure"): self.procedure = [] prcs = requestObject["procedure"].split(",") for prc in prcs: prcName = get_name_from_urn(prc, "procedure", sosConfig) self.procedure.append(prcName) else: self.procedure = None #---------- FEATURES OF INTEREST FILTER self.featureOfInterest = None self.featureOfInterestSpatial = None if requestObject.has_key("featureOfInterest"): foi = requestObject["featureOfInterest"] if foi.find("<ogc:") >= 0 and foi.find("<gml:") >= 0: #raise sosException.SOSException(3,"FOI SPATIAL: %s" %(foi)) self.featureOfInterestSpatial = sosUtils.ogcSpatCons2PostgisSql( foi, 'geom_foi', sosConfig.istsosepsg) else: self.featureOfInterest = get_name_from_urn( foi, "feature", sosConfig) #fois = requestObject["featureOfInterest"].split(",") #for foi in fois: # foiName = get_name_from_urn(foi,"feature") # self.featureOfInterest.append(foiName) #---------- FILTERS FOR QUERY NOT SUPPORTED YET if requestObject.has_key("result"): #raise sosException.SOSException(3,"Parameter \"result\" not yet supported") self.result = sosUtils.ogcCompCons2PostgisSql( requestObject["result"]) else: self.result = None #zero-one optional #---------- RESULT MODEL if requestObject.has_key("resultModel"): if requestObject["resultModel"] in sosConfig.parameters[ "GO_resultModel"]: self.resultModel = requestObject["resultModel"] else: raise sosException.SOSException( 2, "Parameter \"resultModel\" sent with invalid value: supported values are: %s" % ",".join(sosConfig.parameters["GO_resultModel"])) else: self.resultModel = sosConfig.parameters["GO_resultModel"][0] #---------- RESPONSE MODE if requestObject.has_key("responseMode"): if requestObject["responseMode"] in sosConfig.parameters[ "GO_responseMode"]: self.responseMode = requestObject["responseMode"] else: raise sosException.SOSException( 2, "Parameter \"responseMode\" sent with invalid value, supported values are: %s" % (",".join(sosConfig.parameters["GO_responseMode"]))) else: self.responseMode = sosConfig.parameters["GO_responseMode"][0] ########################### # NON STANDARD PARAMETERS # ########################### #---------- AGGREGATE INTERVAL # In ISO 8601 duration format if requestObject.has_key("aggregateInterval"): # Check on the eventTime parameter: it must be only one interval: 2010-01-01T00:00:00+00/2011-01-01T00:00:01+00 exeMsg = "Using aggregate functions, the event time must exist with an interval composed by a begin and an end date (ISO8601)" if self.eventTime == None or len(self.eventTime) != 1 or len( self.eventTime[0]) != 2: raise sosException.SOSException(2, exeMsg) self.aggregate_interval = requestObject["aggregateInterval"] try: iso.parse_duration(self.aggregate_interval) except Exception as ex: raise sosException.SOSException( 2, "Parameter \"aggregate_interval\" sent with invalid format (check ISO8601 duration spec): %s" % ex) else: self.aggregate_interval = None #---------- AGGREGATE FUNCTION # sum,avg,max,min if requestObject.has_key("aggregateFunction"): if self.aggregate_interval == None: raise sosException.SOSException( 2, "Using aggregate functions parameters \"aggregateInterval\" and \"aggregateFunction\" are both mandatory" ) self.aggregate_function = requestObject["aggregateFunction"] if not (self.aggregate_function.upper() in ["AVG", "COUNT", "MAX", "MIN", "SUM"]): raise sosException.SOSException( 2, "Available aggregation functions: avg, count, max, min, sum." ) else: self.aggregate_function = None #---------- AGGREGATE NODATA if requestObject.has_key("aggregateNodata"): if self.aggregate_interval == None or self.aggregate_function == None: raise sosException.SOSException( 2, "Using aggregateNodata parameter requires both \"aggregateInterval\" and \"aggregateFunction\"" ) self.aggregate_nodata = requestObject["aggregateNodata"] else: self.aggregate_nodata = sosConfig.aggregate_nodata #---------- AGGREGATE NODATA QUALITY INDEX if requestObject.has_key("aggregateNodataQi"): if self.aggregate_interval == None or self.aggregate_function == None: raise sosException.SOSException( 2, "Using aggregateNodataQi parameter requires both \"aggregateInterval\" and \"aggregateFunction\"" ) self.aggregate_nodata_qi = requestObject["aggregateNodataQi"] else: self.aggregate_nodata_qi = sosConfig.aggregate_nodata_qi #------------ QUALITY INDEX self.qualityIndex = False if requestObject.has_key("qualityIndex"): if requestObject["qualityIndex"].upper() == "TRUE": self.qualityIndex = True elif requestObject["qualityIndex"].upper() == "FALSE": self.qualityIndex = False else: raise sosException.SOSException( 2, "qualityIndex can only be True or False!") # self.qualityIndex = sosUtils.CQLvalueFilter2PostgisSql("id_qi_fk",requestObject["qualityIndex"]) #********************** if method == "POST": from xml.dom import minidom #---------- THE OFFERING offs = requestObject.getElementsByTagName('offering') if len(offs) == 1: val = offs[0].firstChild if val.nodeType == val.TEXT_NODE: self.offering = get_name_from_urn(str(val.data), "offering", sosConfig) else: err_txt = "XML parsing error (get value: offering)" raise sosException.SOSException(1, err_txt) else: err_txt = "Parameter \"offering\" is mandatory with multiplicity 1" raise sosException.SOSException(1, err_txt) #---------- THE OBSERVED PROPERTY obsProps = requestObject.getElementsByTagName('observedProperty') self.observedProperty = [] if len(obsProps) > 0: for obsProp in obsProps: val = obsProp.firstChild if val.nodeType == val.TEXT_NODE: # get_name_from_urn limit the ability to ask for an observedProperty with LIKE: # eg: ask "water" to get all the water related data, "water:discharge", "water:temperature" ... #self.observedProperty.append(get_name_from_urn(str(val.data),"property")) self.observedProperty.append(str(val.data)) else: err_txt = "XML parsing error (get value: observedProperty)" raise sosException.SOSException(1, err_txt) else: err_txt = "Parameter \"observedProperty\" is mandatory with multiplicity N" raise sosException.SOSException(1, err_txt) #---------- RESPONSE FORMAT respF = requestObject.getElementsByTagName('responseFormat') if len(respF) == 1: val = respF[0].firstChild if val.nodeType == val.TEXT_NODE: self.responseFormat = str(val.data) if self.responseFormat not in sosConfig.parameters[ "GO_responseFormat"]: raise sosException.SOSException( 2, "Parameter \"responseFormat\" sent with invalid value: use one of %s" % "; ".join( sosConfig.parameters["GO_responseFormat"])) else: err_txt = "XML parsing error (get value: responseFormat)" raise sosException.SOSException(1, err_txt) else: err_txt = "Parameter \"responseFormat\" is mandatory with multiplicity 1" raise sosException.SOSException(1, err_txt) #OPTIONAL request parameters #---------- SRS OF RETURNED GML FEATURES srss = requestObject.getElementsByTagName('srsName') if len(srss) > 0: if len(srss) < 2: val = srss[0].firstChild if val.nodeType == val.TEXT_NODE: self.srsName = get_name_from_urn( str(val.data), "refsystem", sosConfig) else: err_txt = "XML parsing error (get value: srsName)" raise sosException.SOSException(1, err_txt) else: err_txt = "Allowed only ONE parameter \"srsName\"" raise sosException.SOSException(1, err_txt) else: self.srsName = sosConfig.parameters["GO_srs"][0] #---------- TIME FILTER evtms = requestObject.getElementsByTagName('eventTime') self.eventTime = [] if len(evtms) > 0: for evtm in evtms: tps = evtm.getElementsByTagName('gml:TimePeriod') for tp in tps: begin = tp.getElementsByTagName('gml:beginPosition') end = tp.getElementsByTagName('gml:endPosition') if len(begin) == 1 and len(end) == 1: Bval = begin[0].firstChild Eval = end[0].firstChild #raise sosException.SOSException(1,end[0].toprettyxml()) if Bval.nodeType == Bval.TEXT_NODE and Eval.nodeType == Eval.TEXT_NODE: self.eventTime.append([ str(Bval.data).replace(" ", "+"), str(Eval.data).replace(" ", "+") ]) #raise sosException.SOSException(1,str(self.eventTime)) else: err_txt = "XML parsing error (get value: TimePeriod)" raise sosException.SOSException(1, err_txt) tis = evtm.getElementsByTagName('gml:TimeInstant') for ti in tis: instant = ti.getElementsByTagName('gml:timePosition') if len(instant) > 0 and len(instant) < 2: Ival = instant[0].firstChild if Ival.nodeType == Ival.TEXT_NODE: self.eventTime.append( [str(Ival.data).replace(" ", "+")]) else: err_txt = "XML parsing error (get value: Timeinstant)" raise sosException.SOSException(1, err_txt) else: self.eventTime = None #---------- PROCEDURES FILTER procs = requestObject.getElementsByTagName('procedure') if len(procs) > 0: self.procedure = [] for proc in procs: if "xlink:href" in proc.attributes.keys(): self.procedure.append( str(proc.getAttribute("xlink:href"))) elif proc.hasChildNodes(): val = proc.firstChild if val.nodeType == val.TEXT_NODE: self.procedure.append( get_name_from_urn(str(val.data), "procedure", sosConfig)) else: err_txt = "XML parsing error (get value: procedure)" raise sosException.SOSException(1, err_txt) else: self.procedure = None #---------- FEATURES OF INTEREST FILTER fets = requestObject.getElementsByTagName('featureOfInterest') self.featureOfInterest = None self.featureOfInterestSpatial = None if len(fets) > 0: if len(fets) < 2: elements = [ e for e in fets[0].childNodes if e.nodeType == e.ELEMENT_NODE ] if len(elements) == 1: self.featureOfInterestSpatial = sosUtils.ogcSpatCons2PostgisSql( elements[0], 'geom_foi', sosConfig.istsosepsg) else: if "xlink:href" in fets[0].attributes.keys(): self.featureOfInterest = str( fets[0].getAttribute("xlink:href")) elif fets[0].hasChildNodes(): val = fets[0].firstChild if val.nodeType == val.TEXT_NODE: self.featureOfInterest = get_name_from_urn( str(val.data), "feature", sosConfig) else: err_txt = "XML parsing error (get value: featureOfInterest)" raise sosException.SOSException(1, err_txt) else: err_txt = "Allowed only ONE parameter \"featureOfInterest\"" raise sosException.SOSException(1, err_txt) #---------- FILTERS FOR QUERY NOT SUPPORTED YET ress = requestObject.getElementsByTagName('result') if len(ress) > 0: raise sosException.SOSException( 3, "Parameter \"result\" not yet supported") else: self.result = None #zero-one optional #---------- RESULT MODEL mods = requestObject.getElementsByTagName('resultModel') if len(mods) > 0: if len(mods) < 2: val = mods[0].firstChild if val.nodeType == val.TEXT_NODE: self.resultModel = str(val.data) if self.resultModel not in sosConfig.parameters[ "GO_resultModel"]: raise sosException.SOSException( 2, "Parameter \"resultModel\" sent with invalid value" ) else: err_txt = "XML parsing error (get value: resultModel)" raise sosException.SOSException(1, err_txt) else: err_txt = "Allowed only ONE parameter \"resultModel\"" raise sosException.SOSException(1, err_txt) else: self.resultModel = None #---------- RESPONSE MODE rsmods = requestObject.getElementsByTagName('responseMode') if len(rsmods) > 0: if len(rsmods) < 2: val = rsmods[0].firstChild if val.nodeType == val.TEXT_NODE: self.responseMode = str(val.data) if self.responseMode not in sosConfig.parameters[ "GO_responseMode"]: raise sosException.SOSException( 2, "Parameter \"responseMode\" sent with invalid value" ) else: err_txt = "XML parsing error (get value: responseMode)" raise sosException.SOSException(1, err_txt) else: err_txt = "Allowed only ONE parameter \"responseMode\"" raise sosException.SOSException(1, err_txt) else: self.responseMode = sosConfig.parameters["GO_responseMode"][0] #-------------- AGGREGATE INTERVAL & FUNCTION self.aggregate_interval = None self.aggregate_function = None aggint = requestObject.getElementsByTagName('aggregateInterval') aggfun = requestObject.getElementsByTagName('aggregateFunction') aggnodata = requestObject.getElementsByTagName('aggregateNodata') if len(aggint) == 1 and len(aggfun) == 1: #----------------------- # -- aggregate_interval #----------------------- # Check on the eventTime parameter: it must be only one interval: 2010-01-01T00:00:00+00/2011-01-01T00:00:01+00 exeMsg = "Using aggregate functions, the event time must exist with an interval composed by a begin and an end date (ISO8601)" if self.eventTime == None or len(self.eventTime) != 1 or len( self.eventTime[0]) != 2: raise sosException.SOSException(2, exeMsg) val = aggint[0].firstChild if val.nodeType == val.TEXT_NODE: self.aggregate_interval = str(val.data) try: iso.parse_duration(self.aggregate_interval) except Exception as ex: raise sosException.SOSException( 2, "Parameter \"aggregate_interval\" sent with invalid format (check ISO8601 duration spec): %s" % ex) else: err_txt = "cannot get ISO8601 duration value in \"aggregateInterval\"" raise sosException.SOSException(1, err_txt) #----------------------- # -- aggregate_function #----------------------- val = aggfun[0].firstChild if val.nodeType == val.TEXT_NODE: self.aggregate_function = str(val.data) if not (self.aggregate_function.upper() in ["AVG", "COUNT", "MAX", "MIN", "SUM"]): raise sosException.SOSException( 2, "Available aggregation functions: avg, count, max, min, sum." ) #----------------------------------- # -- aggregate_no_data default value #----------------------------------- if len(aggnodata) == 1: val = aggnodata[0].firstChild self.aggregate_nodata = str(val.data) else: self.aggregate_nodata = sosConfig.aggregate_nodata #================================ #MISSING AGGREGATE QUALITY INDEX #================================ elif len(aggint) == 0 and len(aggfun) == 0: pass else: err_txt = "\"aggregateInterval\" and \"aggregate_function\" are both required with multiplicity 1" raise sosException.SOSException(1, err_txt) #------------ QUALITY INDEX self.qualityIndex = False qidx = requestObject.getElementsByTagName('qualityIndex') if len(qidx) > 0: if len(qidx) < 2: val = qidx[0].firstChild if val.nodeType == val.TEXT_NODE: self.qualityIndex = str(val.data) if self.qualityIndex.upper() == "TRUE": self.qualityIndex = True elif self.qualityIndex.upper() == "FALSE": pass else: raise sosException.SOSException( 2, "qualityIndex can only be \'True\' or \'False\'" ) elif len(qidx) == 0: pass else: err_txt = "\"qualityIndex\" is allowed with multiplicity 1 only" raise sosException.SOSException(1, err_txt)
def executePost(self, db=True): if self.procedurename is None: raise Exception("POST action without procedure name not allowed") now = datetime.now(iso.UTC) non_blocking_exceptions = [] # Create data array data = self.waEnviron['wsgi_input'].split(";") # Assigned id always in the first position assignedid = data[0] if len(data) == 4: # regular time series mode = self.MODE_REGULAR elif len(data) == 2: # irregular time series mode = self.MODE_IRREGULAR else: raise Exception( "Body content wrongly formatted. Please read the docs.") try: conn = databaseManager.PgDB( self.serviceconf.connection['user'], self.serviceconf.connection['password'], self.serviceconf.connection['dbname'], self.serviceconf.connection['host'], self.serviceconf.connection['port']) rows = conn.select((""" SELECT procedures.id_prc, proc_obs.id_pro, proc_obs.constr_pro, procedures.stime_prc, procedures.etime_prc, procedures.name_prc FROM %s.procedures, %s.proc_obs WHERE proc_obs.id_prc_fk = procedures.id_prc """ % (self.servicename, self.servicename)) + """ AND assignedid_prc = %s ORDER BY proc_obs.id_pro ASC; """, (assignedid, )) if len(rows) == 0: raise Exception("Procedure with aid %s not found." % assignedid) id_prc = rows[0][0] name_prc = rows[0][5] bp = rows[0][3] bpu = False ep = rows[0][4] epu = False def check_sampling(sampling): # If the end position exists the new measures must be after if ep is not None and sampling_time < ep: non_blocking_exceptions.append( "Procedure %s, Sampling time (%s) " "is before the end position (%s)" % (name_prc, sampling_time.isoformat(), ep.isoformat())) return False # Check that the sampling time is before now if sampling_time > now: non_blocking_exceptions.append( "Procedure %s, Sampling time (%s) " "is in the future (%s)" % (name_prc, sampling_time.isoformat(), now.isoformat())) return False return True tmp_data = [] if mode == self.MODE_REGULAR: try: start = iso.parse_datetime(data[1]) except Exception: raise Exception( "Procedure %s, Sampling time (%s) " "wrong format" % name_prc, data[1]) try: step = iso.parse_duration(data[2]) except Exception: raise Exception("Procedure %s, duration (%s) " "wrong format" % (name_prc, data[2])) data = data[3].split("@") for idx in range(0, len(data)): sampling_time = start + (step * idx) if not check_sampling(sampling_time): continue tmp_data.append([sampling_time.isoformat()] + data[idx].split(",")) elif mode == self.MODE_IRREGULAR: data = data[1].split("@") for i in range(0, len(data)): data[i] = data[i].split(",") try: try: sampling_time = iso.parse_datetime(data[i][0]) if not check_sampling(sampling_time): continue except Exception: raise Exception("Procedure %s, Sampling time (%s) " "wrong format" % (name_prc, data[i][0])) tmp_data.append(data[i]) except Exception: non_blocking_exceptions.append( "Procedure %s, Sampling time (%s) " "wrong format" % (name_prc, data[1])) continue data = tmp_data op_cnt = len(rows) for observation in data: id_eti = conn.executeInTransaction((""" INSERT INTO %s.event_time (id_prc_fk, time_eti) """ % self.servicename) + """ VALUES (%s, %s::TIMESTAMPTZ) RETURNING id_eti; """, (id_prc, observation[0])) if (bp is None) or (bp == '') or (iso.parse_datetime( observation[0]) < bp): bp = iso.parse_datetime(observation[0]) bpu = True if (ep is None) or (ep == '') or (iso.parse_datetime( observation[0]) > ep): ep = iso.parse_datetime(observation[0]) epu = True # check if procedure observations length is ok # (-1 remove datetime from lenght of observations array) if op_cnt != (len(observation) - 1): non_blocking_exceptions.append( "Procedure %s, Array length missmatch with procedures " "observation number: %s" % (name_prc, observation)) continue for idx in range(0, op_cnt): try: conn.executeInTransaction( (""" INSERT INTO %s.measures( id_eti_fk, id_qi_fk, id_pro_fk, val_msr ) """ % self.servicename) + """ VALUES (%s, 100, %s, %s); """, ( int(id_eti[0][0]), # id_eti int(rows[idx][1]), # id_pro float(observation[(idx + 1)]))) except Exception as ie: non_blocking_exceptions.append("Procedure %s, %s" % (name_prc, ie)) if bpu: conn.executeInTransaction((""" UPDATE %s.procedures """ % self.servicename) + """ SET stime_prc=%s::TIMESTAMPTZ WHERE id_prc=%s """, (bp.isoformat(), id_prc)) if epu: conn.executeInTransaction((""" UPDATE %s.procedures """ % self.servicename) + """ SET etime_prc=%s::TIMESTAMPTZ WHERE id_prc=%s """, (ep.isoformat(), id_prc)) conn.commitTransaction() # self.setData(ret) self.setMessage("Thanks for data") if len(non_blocking_exceptions) > 0: print >> sys.stderr, str(non_blocking_exceptions) except Exception as e: print >> sys.stderr, traceback.print_exc() #traceback.print_exc(file=sys.stderr) conn.rollbackTransaction() raise Exception("Error in fast insert (%s): %s" % (type(e), e))
def setData(self,pgdb,o,filter): """get data according to request filters""" # @todo mettere da qualche altra parte #SET FOI OF PROCEDURE #========================================= sqlFoi = "SELECT name_fty, name_foi, ST_AsGml(ST_Transform(geom_foi,%s)) as gml, st_x(geom_foi) as x, st_y(geom_foi) as y " %(filter.srsName) sqlFoi += " FROM %s.procedures, %s.foi, %s.feature_type" %(filter.sosConfig.schema,filter.sosConfig.schema,filter.sosConfig.schema) sqlFoi += " WHERE id_foi_fk=id_foi AND id_fty_fk=id_fty AND id_prc=%s" %(o["id_prc"]) try: resFoi = pgdb.select(sqlFoi) except: raise Exception("SQL: %s"%(sqlFoi)) self.featureOfInterest = resFoi[0]["name_foi"] self.foi_urn = filter.sosConfig.urn["feature"] + resFoi[0]["name_fty"] + ":" + resFoi[0]["name_foi"] srs = filter.srsName or filter.sosConfig.istsosepsg if resFoi[0]["gml"].find("srsName")<0: self.foiGml = resFoi[0]["gml"][:resFoi[0]["gml"].find(">")] + " srsName=\"EPSG:%s\"" % srs + resFoi[0]["gml"][resFoi[0]["gml"].find(">"):] else: self.foiGml = resFoi[0]["gml"] self.srs = srs self.x = resFoi[0]["x"] self.y = resFoi[0]["y"] #SET INFORMATION ABOUT OBSERVED_PROPERTIES #========================================= sqlObsPro = "SELECT id_pro, id_opr, name_opr, def_opr, name_uom FROM %s.observed_properties, %s.proc_obs, %s.uoms" %(filter.sosConfig.schema,filter.sosConfig.schema,filter.sosConfig.schema) sqlObsPro += " WHERE id_opr_fk=id_opr AND id_uom_fk=id_uom AND id_prc_fk=%s" %(o["id_prc"]) sqlObsPro += " AND (" #sqlObsPro += " OR ".join(["def_opr='" + str(i) + "'" for i in filter.observedProperty]) sqlObsPro += " OR ".join(["def_opr SIMILAR TO '%(:|)" + str(i) + "(:|)%'" for i in filter.observedProperty]) sqlObsPro += " ) ORDER BY def_opr ASC" try: obspr_res = pgdb.select(sqlObsPro) except: raise Exception("SQL: %s"%(sqlObsPro)) self.observedProperty = [] self.observedPropertyName = [] self.opr_urn = [] self.uom = [] self.qualityIndex = filter.qualityIndex for row in obspr_res: self.observedProperty += [str(row["def_opr"])] self.observedPropertyName +=[str(row["name_opr"])] self.opr_urn += [str(row["def_opr"])] try: #self.uom += [str(row["name_uom"]).encode('utf-8')] self.uom += [row["name_uom"]] except: self.uom += ["n/a"] if self.qualityIndex==True: self.observedProperty += [str(row["def_opr"])+":qualityIndex"] self.observedPropertyName += [str(row["name_opr"])+":qualityIndex"] self.opr_urn += [str(row["def_opr"] +":qualityIndex")] self.uom += ["-"] #SET DATA #=========================================getSampligTime #CASE "insitu-fixed-point" or "insitu-mobile-point" #----------------------------------------- if self.procedureType in ["insitu-fixed-point","insitu-mobile-point"]: sqlSel = "SELECT et.time_eti as t," joinar=[] cols=[] aggrCols=[] aggrNotNull=[] valeFieldName = [] for idx, obspr_row in enumerate(obspr_res): if self.qualityIndex==True: #cols.append("C%s.val_msr as c%s_v, C%s.id_qi_fk as c%s_qi" %(idx,idx,idx,idx)) cols.append("C%s.val_msr as c%s_v, COALESCE(C%s.id_qi_fk,%s) as c%s_qi" %(idx,idx,idx,filter.aggregate_nodata_qi,idx)) valeFieldName.append("c%s_v" %(idx)) valeFieldName.append("c%s_qi" %(idx)) else: cols.append("C%s.val_msr as c%s_v" %(idx,idx)) valeFieldName.append("c%s_v" %(idx)) # If Aggregatation funtion is set #--------------------------------- if filter.aggregate_interval != None: # This can be usefull with string values '''aggrCols.append("CASE WHEN %s(dt.c%s_v) is NULL THEN '%s' ELSE '' || %s(dt.c%s_v) END as c%s_v\n" % ( filter.aggregate_function, idx, filter.aggregate_nodata, filter.aggregate_function, idx, idx) )''' # This accept only numeric results aggrCols.append("COALESCE(%s(dt.c%s_v),'%s') as c%s_v\n" %(filter.aggregate_function,idx,filter.aggregate_nodata,idx)) if self.qualityIndex==True: #raise sosException.SOSException(3,"QI: %s"%(self.qualityIndex)) aggrCols.append("COALESCE(MIN(dt.c%s_qi),%s) as c%s_qi\n" %( idx, filter.aggregate_nodata_qi, idx )) aggrNotNull.append(" c%s_v > -900 " %(idx)) # Set SQL JOINS #--------------- join_txt = " left join (\n" join_txt += " SELECT distinct A%s.id_msr, A%s.val_msr, A%s.id_eti_fk\n" %(idx,idx,idx) if self.qualityIndex==True: join_txt += ",A%s.id_qi_fk\n" %(idx) join_txt += " FROM %s.measures A%s, %s.event_time B%s\n" %(filter.sosConfig.schema,idx,filter.sosConfig.schema,idx) join_txt += " WHERE A%s.id_eti_fk = B%s.id_eti\n" %(idx,idx) join_txt += " AND A%s.id_pro_fk=%s\n" %(idx,obspr_row["id_pro"]) join_txt += " AND B%s.id_prc_fk=%s\n" %(idx,o["id_prc"]) # if qualityIndex has filter #------------------------------ #if filter.qualityIndex and filter.qualityIndex.__class__.__name__=='str': # join_txt += " AND %s\n" %(filter.qualityIndex) # ATTENTION: HERE -999 VALUES ARE EXCLUDED WHEN ASKING AN AGGREAGATE FUNCTION if filter.aggregate_interval != None: # >> Should be removed because measures data is not inserted if there is a nodata value join_txt += " AND A%s.val_msr > -900 " % idx # If eventTime is set add to JOIN part #-------------------------------------- if filter.eventTime: join_txt += " AND (" etf=[] for ft in filter.eventTime: if len(ft)==2: etf.append("B%s.time_eti > timestamptz '%s' AND B%s.time_eti <= timestamptz '%s' \n" %(idx,ft[0],idx,ft[1])) elif len(ft)==1: etf.append("B%s.time_eti = timestamptz '%s' \n" %(idx,ft[0])) else: raise Exception("error in time filter") join_txt += " OR ".join(etf) join_txt += ")\n" else: join_txt += " AND B%s.time_eti = (SELECT max(time_eti) FROM %s.event_time WHERE id_prc_fk=%s) \n" %(idx,filter.sosConfig.schema,o["id_prc"]) # close SQL JOINS #----------------- join_txt += " ) as C%s\n" %(idx) join_txt += " on C%s.id_eti_fk = et.id_eti" %(idx) joinar.append(join_txt) #If MOBILE PROCEDURE #-------------------- if self.procedureType=="insitu-mobile-point": join_txt = " left join (\n" join_txt += " SELECT distinct Ax.id_pos, X(ST_Transform(Ax.geom_pos,%s)) as x,Y(ST_Transform(Ax.geom_pos,%s)) as y,Z(ST_Transform(Ax.geom_pos,%s)) as z, Ax.id_eti_fk\n" %(filter.srsName,filter.srsName,filter.srsName) if self.qualityIndex==True: join_txt += ", Ax.id_qi_fk as posqi\n" join_txt += " FROM %s.positions Ax, %s.event_time Bx\n" %(filter.sosConfig.schema,filter.sosConfig.schema) join_txt += " WHERE Ax.id_eti_fk = Bx.id_eti" join_txt += " AND Bx.id_prc_fk=%s" %(o["id_prc"]) if filter.eventTime: join_txt += " AND (" etf=[] for ft in filter.eventTime: if len(ft)==2: etf.append("Bx.time_eti > timestamptz '%s' AND Bx.time_eti <= timestamptz '%s' " %(ft[0],ft[1])) elif len(ft)==1: etf.append("Bx.time_eti = timestamptz '%s' " %(ft[0])) else: raise Exception("error in time filter") join_txt += " OR ".join(etf) join_txt += ")\n" else: join_txt += " AND Bx.time_eti = (SELECT max(time_eti) FROM %s.event_time WHERE id_prc_fk=%s) " %(filter.sosConfig.schema,o["id_prc"]) join_txt += " ) as Cx on Cx.id_eti_fk = et.id_eti\n" sqlSel += " Cx.x as x, Cx.y as y, Cx.z as z, " if self.qualityIndex==True: #sqlSel += "COALESCE(Cx.posqi,%s) as posqi, " % filter.aggregate_nodata_qi sqlSel += "Cx.posqi, " joinar.append(join_txt) # Set FROM CLAUSE #----------------- sqlSel += ", ".join(cols) sqlSel += " FROM %s.event_time et\n" %(filter.sosConfig.schema) #==================== # Set WHERE CLAUSES #==================== sqlData = " ".join(joinar) sqlData += " WHERE et.id_prc_fk=%s\n" %(o["id_prc"]) # Set FILTER ON RESULT (OGC:COMPARISON) - #---------------------------------------- if filter.result: for ind, ov in enumerate(self.observedProperty): if ov.find(filter.result[0])>0: sqlData += " AND C%s.val_msr %s" %(ind,filter.result[1]) #sqlData += " AND C%s.val_msr %s" %(self.observedProperty.index(filter.result[0]),filter.result[1]) # Set FILTER ON EVENT-TIME - #--------------------------- if filter.eventTime: sqlData += " AND (" etf=[] for ft in filter.eventTime: if len(ft)==2: etf.append("et.time_eti > timestamptz '%s' AND et.time_eti <= timestamptz '%s' " %(ft[0],ft[1])) elif len(ft)==1: etf.append("et.time_eti = timestamptz '%s' " %(ft[0])) else: raise Exception("error in time filter") sqlData += " OR ".join(etf) sqlData += ")" else: sqlData += " AND et.time_eti = (SELECT max(time_eti) FROM %s.event_time WHERE id_prc_fk=%s) " %(filter.sosConfig.schema,o["id_prc"]) sqlData += " ORDER by et.time_eti" sql = sqlSel+sqlData # if filter.aggregate_interval != None: self.aggregate_function = filter.aggregate_function.upper() ''' for i in range(0,len(self.observedProperty)): self.observedProperty[i] = "%s:%s" % (self.observedProperty[i], filter.aggregate_function) for ob in self.observedProperty: ob = "%s:%s" % (ob, filter.aggregate_function)''' # Interval preparation # Converting ISO 8601 duration isoInt = iso.parse_duration(filter.aggregate_interval) sqlInt = "" if isinstance(isoInt, timedelta): if isoInt.days>0: sqlInt += "%s days " % isoInt.days if isoInt.seconds>0: sqlInt += "%s seconds " % isoInt.seconds elif isinstance(isoInt, iso.Duration): if isoInt.years>0: sqlInt += "%s years " % isoInt.years if isoInt.months>0: isoInt.months = int(isoInt.months) sqlInt += "%s months " % isoInt.months if isoInt.days>0: sqlInt += "%s days " % isoInt.days if isoInt.seconds>0: sqlInt += "%s seconds " % isoInt.seconds # @todo improve this part # calculate how many step are included in the asked interval. hopBefore = 1 hop = 0 tmpStart = iso.parse_datetime(filter.eventTime[0][0]) tmpEnd = self.samplingTime[1] while (tmpStart+isoInt)<=tmpEnd and (tmpStart+isoInt)<=iso.parse_datetime(filter.eventTime[0][1]): if tmpStart < self.samplingTime[0]: hopBefore+=1 hop+=1 elif (tmpStart >= self.samplingTime[0]) and ((tmpStart+isoInt)<=self.samplingTime[1]): hop+=1 tmpStart=tmpStart+isoInt aggregationSQL = "SELECT ts.sint as t, %s\n" aggregationSQL += "FROM\n" aggregationSQL += " (\n" # Generating time series here aggregationSQL += " select\n" aggregationSQL += " (('%s'::TIMESTAMP WITH TIME ZONE) \n" aggregationSQL += " + s.a * '%s'::interval)::TIMESTAMP WITH TIME ZONE as sint\n" aggregationSQL += " from generate_series(%s, %s) as s(a)\n" aggregationSQL += " ) as ts LEFT JOIN ( \n\n" aggregationSQL += " %s \n\n" aggregationSQL += " ) as dt\n" aggregationSQL += " ON (\n" aggregationSQL += " dt.t > (ts.sint-'%s'::interval)\n" aggregationSQL += " AND\n" aggregationSQL += " dt.t <= (ts.sint) \n" aggregationSQL += " )\n" aggregationSQL += " GROUP BY ts.sint\n" aggregationSQL += " ORDER BY ts.sint" sql = aggregationSQL % (", ".join(aggrCols), filter.eventTime[0][0], sqlInt, hopBefore, hop, sql, sqlInt) else: self.aggregate_function = None #print sql.replace('\n','') try: data_res = pgdb.select(sql) except: raise Exception("SQL: %s"%(sql)) #------------------------------------ #--------- APPEND DATA IN ARRAY ----- #------------------------------------ #append data for line in data_res: if self.procedureType=="insitu-fixed-point": data_array = [line["t"]] elif self.procedureType=="insitu-mobile-point": if self.qualityIndex==True: data_array = [line["t"],line["x"],line["y"],line["z"],line["posqi"]] else: data_array = [line["t"],line["x"],line["y"],line["z"]] data_array.extend([line[field] for field in valeFieldName]) self.data.append(data_array) #----------------------------------------- #CASE "virtual" #----------------------------------------- elif self.procedureType in ["virtual"]: self.aggregate_function = filter.aggregate_function self.aggregate_interval = filter.aggregate_interval self.aggregate_nodata = filter.aggregate_nodata self.aggregate_nodata_qi = filter.aggregate_nodata_qi vpFolder = os.path.join(os.path.join(filter.sosConfig.virtual_processes_folder,self.name)) if not os.path.isfile("%s/%s.py" % (vpFolder,self.name)): raise Exception("Virtual procedure folder does not contain any Virtual Procedure code for %s" % self.name) #----- VIRTUAL PROCESS LOADING ----- try: sys.path.append(vpFolder) except: raise Exception("error in loading virtual procedure path") #import procedure process exec "import %s as vproc" %(self.name) # Initialization of virtual procedure will load the source data vp = vproc.istvp() vp._configure(filter, pgdb) # Calculate virtual procedure data vp.calculateObservations(self)
def applyFunction(ob, filter): import copy try: # Create array container begin = iso.parse_datetime(filter.eventTime[0][0]) end = iso.parse_datetime(filter.eventTime[0][1]) duration = iso.parse_duration(filter.aggregate_interval) result = {} dt = begin fields = len(ob.observedProperty)# + 1 # +1 timestamp field not mentioned in the observedProperty array while dt < end: dt2 = dt + duration result[dt2]=[] for c in range(fields): result[dt2].append([]) d = 0 data = copy.copy(ob.data) while len(data) > 0: tmp = data.pop(d) if dt < tmp[0] and tmp[0] <= dt2: ob.data.pop(d) for c in range(fields): result[dt2][c].append(float(tmp[c+1])) elif dt > tmp[0]: ob.data.pop(d) elif dt2 < tmp[0]: break dt = dt2 data = [] for r in sorted(result): record = [r] for v in range(len(result[r])): if ob.observedProperty[v].split(":")[-1]=="qualityIndex": if len(result[r][v])==0: record.append(filter.aggregate_nodata_qi) else: record.append(int(min(result[r][v]))) else: val = None if len(result[r][v])==0: val = filter.aggregate_nodata elif filter.aggregate_function.upper() == 'SUM': val = sum(result[r][v]) elif filter.aggregate_function.upper() == 'MAX': val = max(result[r][v]) elif filter.aggregate_function.upper() == 'MIN': val = min(result[r][v]) elif filter.aggregate_function.upper() == 'AVG': val = round(sum(result[r][v])/len(result[r][v]),4) elif filter.aggregate_function.upper() == 'COUNT': val = len(result[r][v]) record.append(val) data.append(record) ob.data = data except Exception as e: raise Exception("Error while applying aggregate function on virtual procedures: %s" % (e))
def __init__(self,sosRequest,method,requestObject,sosConfig): f.sosFilter.__init__(self,sosRequest,method,requestObject,sosConfig) # @TODO Declare attribute first! # self.offering = None # etc.. #************************** if method == "GET": #---------- THE OFFERING if requestObject.has_key("offering"): self.offering = get_name_from_urn(requestObject["offering"],"offering",sosConfig) else: raise sosException.SOSException(1,"Parameter \"offering\" is mandatory with multiplicity 1") #---------- THE OBSERVED PROPERTY if requestObject.has_key("observedProperty"): self.observedProperty = [] oprs = requestObject["observedProperty"].split(",") for opr in oprs: # get_name_from_urn limit the ability to ask for an observedProperty with LIKE: # eg: ask "water" to get all the water related data, "water:discharge", "water:temperature" ... #oprName = get_name_from_urn(opr,"property") oprName = opr self.observedProperty.append(oprName) # one-many ID else: raise sosException.SOSException(1,"Parameter \"observedProperty\" is mandatory with multiplicity N") #---------- RESPONSE FORMAT if requestObject.has_key("responseFormat"): if not requestObject["responseFormat"] in sosConfig.parameters["GO_responseFormat"]: raise sosException.SOSException(2,"Parameter \"responseFormat\" sent with invalid value : use one of %s" % "; ".join(sosConfig.parameters["GO_responseFormat"])) else: self.responseFormat = requestObject["responseFormat"] else: raise sosException.SOSException(1,"Parameter \"responseFormat\" is mandatory with multiplicity 1") #one #OPTIONAL request parameters #---------- SRS FILTER if requestObject.has_key("srsName"): self.srsName = get_name_from_urn(requestObject["srsName"],"refsystem",sosConfig) if not self.srsName in sosConfig.parameters["GO_srs"]: raise sosException.SOSException(2,"srsName \"%s\" not supported, use one of: %s" %(self.srsName,",".join(sosConfig.parameters["GO_srs"]))) else: self.srsName = sosConfig.parameters["GO_srs"][0] #---------- TIME FILTER if requestObject.has_key('eventTime'): self.eventTime = [] for i in requestObject["eventTime"].replace(" ","+").split(","): if len(i.split("/")) < 3: self.eventTime.append(i.split("/")) else: raise sosException.SOSException(2,"Parameter \"eventTime\" bad formatted") tp=[] for t in self.eventTime: if len(t) == 2: tp.append(iso.parse_datetime(t[0])) tp.append(iso.parse_datetime(t[1])) if len(t)==1: tp.append(iso.parse_datetime(t[0])) # Checking if some event limitation is reached #if sosConfig["maxGoPeriod"]: if int(sosConfig.maxGoPeriod) > 0: from datetime import timedelta d = timedelta(hours=int(sosConfig.maxGoPeriod)) userPeriod = max(tp)-min(tp) if d < userPeriod: raise sosException.SOSException(2,"You are requesting data for a period of [%s hours], but you are not permitted to ask for a period longer than: %s hours" % (userPeriod,d)) else: self.eventTime = None #---------- PROCEDURES FILTER if requestObject.has_key("procedure"): self.procedure = [] prcs = requestObject["procedure"].split(",") for prc in prcs: prcName = get_name_from_urn(prc,"procedure",sosConfig) self.procedure.append(prcName) else: self.procedure = None #---------- FEATURES OF INTEREST FILTER self.featureOfInterest = None self.featureOfInterestSpatial = None if requestObject.has_key("featureOfInterest"): foi = requestObject["featureOfInterest"] if foi.find("<ogc:")>=0 and foi.find("<gml:")>=0: #raise sosException.SOSException(3,"FOI SPATIAL: %s" %(foi)) self.featureOfInterestSpatial = sosUtils.ogcSpatCons2PostgisSql(foi,'geom_foi',sosConfig.istsosepsg) else: self.featureOfInterest = get_name_from_urn(foi,"feature",sosConfig) #fois = requestObject["featureOfInterest"].split(",") #for foi in fois: # foiName = get_name_from_urn(foi,"feature") # self.featureOfInterest.append(foiName) #---------- FILTERS FOR QUERY NOT SUPPORTED YET if requestObject.has_key("result"): #raise sosException.SOSException(3,"Parameter \"result\" not yet supported") self.result = sosUtils.ogcCompCons2PostgisSql(requestObject["result"]) else: self.result = None #zero-one optional #---------- RESULT MODEL if requestObject.has_key("resultModel"): if requestObject["resultModel"] in sosConfig.parameters["GO_resultModel"]: self.resultModel = requestObject["resultModel"] else: raise sosException.SOSException(2,"Parameter \"resultModel\" sent with invalid value: supported values are: %s" %",".join(sosConfig.parameters["GO_resultModel"])) else: self.resultModel = sosConfig.parameters["GO_resultModel"][0] #---------- RESPONSE MODE if requestObject.has_key("responseMode"): if requestObject["responseMode"] in sosConfig.parameters["GO_responseMode"]: self.responseMode = requestObject["responseMode"] else: raise sosException.SOSException(2,"Parameter \"responseMode\" sent with invalid value, supported values are: %s" %(",".join(sosConfig.parameters["GO_responseMode"]))) else: self.responseMode = sosConfig.parameters["GO_responseMode"][0] ########################### # NON STANDARD PARAMETERS # ########################### #---------- AGGREGATE INTERVAL # In ISO 8601 duration format if requestObject.has_key("aggregateInterval"): # Check on the eventTime parameter: it must be only one interval: 2010-01-01T00:00:00+00/2011-01-01T00:00:01+00 exeMsg = "Using aggregate functions, the event time must exist with an interval composed by a begin and an end date (ISO8601)" if self.eventTime == None or len(self.eventTime)!=1 or len(self.eventTime[0])!=2: raise sosException.SOSException(2,exeMsg) self.aggregate_interval = requestObject["aggregateInterval"] try: iso.parse_duration(self.aggregate_interval) except Exception as ex: raise sosException.SOSException(2,"Parameter \"aggregate_interval\" sent with invalid format (check ISO8601 duration spec): %s" % ex) else: self.aggregate_interval = None #---------- AGGREGATE FUNCTION # sum,avg,max,min if requestObject.has_key("aggregateFunction"): if self.aggregate_interval==None: raise sosException.SOSException(2,"Using aggregate functions parameters \"aggregateInterval\" and \"aggregateFunction\" are both mandatory") self.aggregate_function = requestObject["aggregateFunction"] if not (self.aggregate_function.upper() in ["AVG","COUNT","MAX","MIN","SUM"]): raise sosException.SOSException(2,"Available aggregation functions: avg, count, max, min, sum.") else: self.aggregate_function = None #---------- AGGREGATE NODATA if requestObject.has_key("aggregateNodata"): if self.aggregate_interval==None or self.aggregate_function==None: raise sosException.SOSException(2,"Using aggregateNodata parameter requires both \"aggregateInterval\" and \"aggregateFunction\"") self.aggregate_nodata = requestObject["aggregateNodata"] else: self.aggregate_nodata = sosConfig.aggregate_nodata #---------- AGGREGATE NODATA QUALITY INDEX if requestObject.has_key("aggregateNodataQi"): if self.aggregate_interval==None or self.aggregate_function==None: raise sosException.SOSException(2,"Using aggregateNodataQi parameter requires both \"aggregateInterval\" and \"aggregateFunction\"") self.aggregate_nodata_qi = requestObject["aggregateNodataQi"] else: self.aggregate_nodata_qi = sosConfig.aggregate_nodata_qi #------------ QUALITY INDEX self.qualityIndex=False if requestObject.has_key("qualityIndex"): if requestObject["qualityIndex"].upper() == "TRUE": self.qualityIndex = True elif requestObject["qualityIndex"].upper() == "FALSE": self.qualityIndex = False else: raise sosException.SOSException(2,"qualityIndex can only be True or False!") # self.qualityIndex = sosUtils.CQLvalueFilter2PostgisSql("id_qi_fk",requestObject["qualityIndex"]) #********************** if method == "POST": from xml.dom import minidom #---------- THE OFFERING offs = requestObject.getElementsByTagName('offering') if len(offs) == 1: val = offs[0].firstChild if val.nodeType == val.TEXT_NODE: self.offering = get_name_from_urn(str(val.data),"offering",sosConfig) else: err_txt = "XML parsing error (get value: offering)" raise sosException.SOSException(1,err_txt) else: err_txt = "Parameter \"offering\" is mandatory with multiplicity 1" raise sosException.SOSException(1,err_txt) #---------- THE OBSERVED PROPERTY obsProps = requestObject.getElementsByTagName('observedProperty') self.observedProperty = [] if len(obsProps) > 0: for obsProp in obsProps: val = obsProp.firstChild if val.nodeType == val.TEXT_NODE: # get_name_from_urn limit the ability to ask for an observedProperty with LIKE: # eg: ask "water" to get all the water related data, "water:discharge", "water:temperature" ... #self.observedProperty.append(get_name_from_urn(str(val.data),"property")) self.observedProperty.append(str(val.data)) else: err_txt = "XML parsing error (get value: observedProperty)" raise sosException.SOSException(1,err_txt) else: err_txt = "Parameter \"observedProperty\" is mandatory with multiplicity N" raise sosException.SOSException(1,err_txt) #---------- RESPONSE FORMAT respF = requestObject.getElementsByTagName('responseFormat') if len(respF) == 1: val = respF[0].firstChild if val.nodeType == val.TEXT_NODE: self.responseFormat = str(val.data) if self.responseFormat not in sosConfig.parameters["GO_responseFormat"]: raise sosException.SOSException(2,"Parameter \"responseFormat\" sent with invalid value: use one of %s" % "; ".join(sosConfig.parameters["GO_responseFormat"])) else: err_txt = "XML parsing error (get value: responseFormat)" raise sosException.SOSException(1,err_txt) else: err_txt = "Parameter \"responseFormat\" is mandatory with multiplicity 1" raise sosException.SOSException(1,err_txt) #OPTIONAL request parameters #---------- SRS OF RETURNED GML FEATURES srss = requestObject.getElementsByTagName('srsName') if len(srss) > 0: if len(srss) < 2: val = srss[0].firstChild if val.nodeType == val.TEXT_NODE: self.srsName = get_name_from_urn(str(val.data),"refsystem",sosConfig) else: err_txt = "XML parsing error (get value: srsName)" raise sosException.SOSException(1,err_txt) else: err_txt = "Allowed only ONE parameter \"srsName\"" raise sosException.SOSException(1,err_txt) else: self.srsName = sosConfig.parameters["GO_srs"][0] #---------- TIME FILTER evtms = requestObject.getElementsByTagName('eventTime') self.eventTime = [] if len(evtms) > 0: for evtm in evtms: tps = evtm.getElementsByTagName('gml:TimePeriod') for tp in tps: begin = tp.getElementsByTagName('gml:beginPosition') end = tp.getElementsByTagName('gml:endPosition') if len(begin)==1 and len(end)==1: Bval = begin[0].firstChild Eval = end[0].firstChild #raise sosException.SOSException(1,end[0].toprettyxml()) if Bval.nodeType == Bval.TEXT_NODE and Eval.nodeType == Eval.TEXT_NODE: self.eventTime.append([str(Bval.data).replace(" ","+"),str(Eval.data).replace(" ","+")]) #raise sosException.SOSException(1,str(self.eventTime)) else: err_txt = "XML parsing error (get value: TimePeriod)" raise sosException.SOSException(1,err_txt) tis = evtm.getElementsByTagName('gml:TimeInstant') for ti in tis: instant = ti.getElementsByTagName('gml:timePosition') if len(instant)>0 and len(instant)<2: Ival = instant[0].firstChild if Ival.nodeType == Ival.TEXT_NODE: self.eventTime.append([str(Ival.data).replace(" ","+")]) else: err_txt = "XML parsing error (get value: Timeinstant)" raise sosException.SOSException(1,err_txt) else: self.eventTime = None #---------- PROCEDURES FILTER procs = requestObject.getElementsByTagName('procedure') if len(procs) > 0: self.procedure=[] for proc in procs: if "xlink:href" in proc.attributes.keys(): self.procedure.append(str(proc.getAttribute("xlink:href"))) elif proc.hasChildNodes(): val = proc.firstChild if val.nodeType == val.TEXT_NODE: self.procedure.append(get_name_from_urn(str(val.data),"procedure",sosConfig)) else: err_txt = "XML parsing error (get value: procedure)" raise sosException.SOSException(1,err_txt) else: self.procedure = None #---------- FEATURES OF INTEREST FILTER fets = requestObject.getElementsByTagName('featureOfInterest') self.featureOfInterest = None self.featureOfInterestSpatial = None if len(fets)>0: if len(fets)<2: elements = [e for e in fets[0].childNodes if e.nodeType == e.ELEMENT_NODE] if len(elements)==1: self.featureOfInterestSpatial = sosUtils.ogcSpatCons2PostgisSql(elements[0],'geom_foi',sosConfig.istsosepsg) else: if "xlink:href" in fets[0].attributes.keys(): self.featureOfInterest = str(fets[0].getAttribute("xlink:href")) elif fets[0].hasChildNodes(): val = fets[0].firstChild if val.nodeType == val.TEXT_NODE: self.featureOfInterest = get_name_from_urn(str(val.data),"feature",sosConfig) else: err_txt = "XML parsing error (get value: featureOfInterest)" raise sosException.SOSException(1,err_txt) else: err_txt = "Allowed only ONE parameter \"featureOfInterest\"" raise sosException.SOSException(1,err_txt) #---------- FILTERS FOR QUERY NOT SUPPORTED YET ress = requestObject.getElementsByTagName('result') if len(ress)>0: raise sosException.SOSException(3,"Parameter \"result\" not yet supported") else: self.result = None #zero-one optional #---------- RESULT MODEL mods = requestObject.getElementsByTagName('resultModel') if len(mods)>0: if len(mods)<2: val = mods[0].firstChild if val.nodeType == val.TEXT_NODE: self.resultModel = str(val.data) if self.resultModel not in sosConfig.parameters["GO_resultModel"]: raise sosException.SOSException(2,"Parameter \"resultModel\" sent with invalid value") else: err_txt = "XML parsing error (get value: resultModel)" raise sosException.SOSException(1,err_txt) else: err_txt = "Allowed only ONE parameter \"resultModel\"" raise sosException.SOSException(1,err_txt) else: self.resultModel = None #---------- RESPONSE MODE rsmods = requestObject.getElementsByTagName('responseMode') if len(rsmods)>0: if len(rsmods)<2: val = rsmods[0].firstChild if val.nodeType == val.TEXT_NODE: self.responseMode = str(val.data) if self.responseMode not in sosConfig.parameters["GO_responseMode"]: raise sosException.SOSException(2,"Parameter \"responseMode\" sent with invalid value") else: err_txt = "XML parsing error (get value: responseMode)" raise sosException.SOSException(1,err_txt) else: err_txt = "Allowed only ONE parameter \"responseMode\"" raise sosException.SOSException(1,err_txt) else: self.responseMode = sosConfig.parameters["GO_responseMode"][0] #-------------- AGGREGATE INTERVAL & FUNCTION self.aggregate_interval = None self.aggregate_function = None aggint = requestObject.getElementsByTagName('aggregateInterval') aggfun = requestObject.getElementsByTagName('aggregateFunction') aggnodata = requestObject.getElementsByTagName('aggregateNodata') if len(aggint)==1 and len(aggfun)==1: #----------------------- # -- aggregate_interval #----------------------- # Check on the eventTime parameter: it must be only one interval: 2010-01-01T00:00:00+00/2011-01-01T00:00:01+00 exeMsg = "Using aggregate functions, the event time must exist with an interval composed by a begin and an end date (ISO8601)" if self.eventTime == None or len(self.eventTime)!=1 or len(self.eventTime[0])!=2: raise sosException.SOSException(2,exeMsg) val = aggint[0].firstChild if val.nodeType == val.TEXT_NODE: self.aggregate_interval = str(val.data) try: iso.parse_duration(self.aggregate_interval) except Exception as ex: raise sosException.SOSException(2,"Parameter \"aggregate_interval\" sent with invalid format (check ISO8601 duration spec): %s" % ex) else: err_txt = "cannot get ISO8601 duration value in \"aggregateInterval\"" raise sosException.SOSException(1,err_txt) #----------------------- # -- aggregate_function #----------------------- val = aggfun[0].firstChild if val.nodeType == val.TEXT_NODE: self.aggregate_function = str(val.data) if not (self.aggregate_function.upper() in ["AVG","COUNT","MAX","MIN","SUM"]): raise sosException.SOSException(2,"Available aggregation functions: avg, count, max, min, sum.") #----------------------------------- # -- aggregate_no_data default value #----------------------------------- if len(aggnodata)==1: val = aggnodata[0].firstChild self.aggregate_nodata = str(val.data) else: self.aggregate_nodata = sosConfig.aggregate_nodata #================================ #MISSING AGGREGATE QUALITY INDEX #================================ elif len(aggint)==0 and len(aggfun)==0: pass else: err_txt = "\"aggregateInterval\" and \"aggregate_function\" are both required with multiplicity 1" raise sosException.SOSException(1,err_txt) #------------ QUALITY INDEX self.qualityIndex=False qidx = requestObject.getElementsByTagName('qualityIndex') if len(qidx)>0: if len(qidx)<2: val = qidx[0].firstChild if val.nodeType == val.TEXT_NODE: self.qualityIndex = str(val.data) if self.qualityIndex.upper() == "TRUE": self.qualityIndex=True elif self.qualityIndex.upper() == "FALSE": pass else: raise sosException.SOSException(2,"qualityIndex can only be \'True\' or \'False\'") elif len(qidx)==0: pass else: err_txt = "\"qualityIndex\" is allowed with multiplicity 1 only" raise sosException.SOSException(1,err_txt)
def __init__(self, sosRequest, method, requestObject, sosConfig): f.sosFilter.__init__(self, sosRequest, method, requestObject, sosConfig) if method == "GET": self.eventTime = None self.featureOfInterest = None self.featureOfInterestSpatial = None self.result = None #zero-one optional self.observedProperty = [':'] # OBSERVED PROPERTY # get_name_from_urn limit the ability to ask for an observedProperty with LIKE: # eg: ask "water" to get all the water related data, "water:discharge", "water:temperature" ... if requestObject.has_key("observedproperty"): self.observedProperty = [] oprs = requestObject["observedproperty"].split(",") for opr in oprs: if opr == '': raise sosException.SOSException( "MissingParameterValue", "observedProperty", "Missing 'observedProperty' parameter") oprName = opr self.observedProperty.append(oprName) # one-many ID # PROCEDURES FILTER if requestObject.has_key("procedure"): self.procedure = [] prcs = requestObject["procedure"].split(",") for prc in prcs: if prc == '': raise sosException.SOSException( "MissingParameterValue", "procedure", "Missing 'procedure' parameter") try: prcName = get_name_from_urn(prc, "procedure", sosConfig) except Exception as e: raise sosException.SOSException( "InvalidParameterValue", "procedure", str(e)) self.procedure.append(prcName) else: self.procedure = None if self.version == '2.0.0': # THE OFFERING # > in istSOS offerings are equals to procedures # > so offerings are inserted into the procedure array filter if requestObject.has_key("offering"): prcs = requestObject["offering"].split(",") if self.procedure == None: self.procedure = [] for prc in prcs: if prc == '': raise sosException.SOSException( "MissingParameterValue", "offering", "Missing 'offering' parameter") try: prcName = get_name_from_urn( prc, "offering", sosConfig) except Exception as e: raise sosException.SOSException( "InvalidParameterValue", "offering", str(e)) # Check for name redundancy if prcName not in self.procedure: self.procedure.append(prcName) # RESPONSE FORMAT self.responseFormat = 'text/xml;subtype="om/2.0"' if requestObject.has_key("responseformat"): if requestObject["responseformat"] == '': raise sosException.SOSException( "MissingParameterValue", "responseformat", "Missing 'responseformat' parameter") if not requestObject[ "responseformat"] in sosConfig.parameters[ "GO_responseFormat_2_0_0"]: raise sosException.SOSException( "InvalidParameterValue", "responseFormat", "Parameter \"responseFormat\" sent with invalid value : use one of %s" % "; ".join(sosConfig. parameters["GO_responseFormat_2_0_0"])) elif requestObject[ "responseformat"] == sosConfig.parameters[ "GO_responseFormat_2_0_0"][0]: self.responseFormat = 'text/xml;subtype="om/2.0"' else: self.responseFormat = requestObject["responseformat"] # OPTIONAL SRS FILTER if requestObject.has_key("crs"): try: self.srsName = requestObject["crs"].split(':')[-1] except Exception as e: raise sosException.SOSException( "InvalidParameterValue", "crs", "%s" % e) if not self.srsName in sosConfig.parameters["GO_srs"]: raise sosException.SOSException( "InvalidParameterValue", "crs", "crs \"%s\" not supported, use one of: %s" % (self.srsName, ",".join( sosConfig.parameters["GO_srs"]))) else: self.srsName = sosConfig.parameters["GO_srs"][0] # TIME FILTER # istSOS supports # kvp examples: # - during: temporalFilter=om:phenomenonTime,2012-11-19T14:00:00+01:00/2012-11-19T14:15:00+01:00 # - equals: temporalFilter=om:phenomenonTime,2012-11-19T14:00:00.000+01:00 # - combination: temporalFilter=om:phenomenonTime,2012-11-19T14:00:00+01:00/2012-11-19T14:15:00+01:00,2012-11-19T14:00:00.000+01:00 if 'temporalfilter' in requestObject: self.eventTime = [] temporalfilter = requestObject["temporalfilter"].replace( " ", "+").split(",") # > in istSOS om:phenomenonTime is equals to om:resultTime if temporalfilter.pop(0) not in [ 'om:phenomenonTime', 'phenomenonTime', 'om:resultTime', 'resultTime' ]: raise sosException.SOSException( "InvalidParameterValue", "temporalfilter", "Parameter \"temporalFilter\" bad formatted") for i in temporalfilter: if '/' in i: interval = i.split("/") if len(interval) != 2: raise sosException.SOSException( "InvalidParameterValue", "temporalfilter", "Parameter \"temporalfilter\" bad formatted" ) try: iso.parse_date(interval[0]) iso.parse_date(interval[1]) except iso.ISO8601Error as isoerr: raise sosException.SOSException( "InvalidParameterValue", "temporalfilter", "Parameter \"temporalfilter\" bad formatted, %s" % isoerr) self.eventTime.append(interval) else: try: iso.parse_date(i) except iso.ISO8601Error as isoerr: raise sosException.SOSException( "InvalidParameterValue", "temporalfilter", "Parameter \"temporalfilter\" bad formatted, %s" % isoerr) self.eventTime.append([i]) # FEATURES OF INTEREST FILTER if requestObject.has_key("featureofinterest"): if requestObject["featureofinterest"] == '': raise sosException.SOSException( "MissingParameterValue", "featureOfInterest", "Missing 'featureOfInterest' parameter") if sosConfig.urn["feature"] in requestObject[ "featureofinterest"]: self.featureOfInterest = get_name_from_urn( requestObject["featureofinterest"], "feature", sosConfig) else: self.featureOfInterest = requestObject[ "featureofinterest"] # SPATIAL FILTER # example1: spatialFilter=om:featureOfInterest/*/sams:shape,0.0,0.0,60.0,60.0,http://www.opengis.net/def/crs/EPSG/0/4326 # example2: spatialFilter=om:featureOfInterest/*/sams:shape,0.0,0.0,60.0,60.0,urn:ogc:def:crs:EPSG::4326 if requestObject.has_key("spatialfilter"): sfs = requestObject["spatialfilter"].split(",") if len(sfs) != 6: raise sosException.SOSException( "InvalidParameterValue", "spatialfilter", "Invalid spatial filter '%s'" % requestObject["spatialfilter"]) if sfs[0] != 'om:featureOfInterest/*/sams:shape': raise sosException.SOSException( "InvalidParameterValue", "spatialfilter", "Invalid spatial filter '%s'" % requestObject["spatialfilter"]) srsName = None if sfs[5].index(':') > -1: srsName = sfs[5].split(':')[-1] if sfs[5].index('/') > -1: srsName = sfs[5].split('/')[-1] ogcfilter = ( "<ogc:BBOX>" + "<ogc:PropertyName>the_geom</ogc:PropertyName>" + ("<gml:Box srsName='EPSG:%s'>" % (srsName)) + ("<gml:coordinates>%s,%s %s,%s</gml:coordinates>" % (sfs[1], sfs[2], sfs[3], sfs[4])) + "</gml:Box>" + "</ogc:BBOX>") self.featureOfInterestSpatial = sosUtils.ogcSpatCons2PostgisSql( ogcfilter, 'geom_foi', sosConfig.istsosepsg) else: # THE OFFERING if requestObject.has_key("offering"): try: self.offering = get_name_from_urn( requestObject["offering"], "offering", sosConfig) except Exception as e: raise sosException.SOSException( "InvalidParameterValue", "offering", str(e)) # RESPONSE FORMAT if requestObject.has_key("responseformat"): if requestObject["responseformat"] == '': raise sosException.SOSException( "MissingParameterValue", "responseFormat", "Missing 'responseFormat' parameter") if not requestObject[ "responseformat"] in sosConfig.parameters[ "GO_responseFormat"]: raise sosException.SOSException( "InvalidParameterValue", "responseFormat", "Parameter \"responseFormat\" sent with invalid value : use one of %s" % "; ".join( sosConfig.parameters["GO_responseFormat"])) else: self.responseFormat = requestObject["responseformat"] if not requestObject.has_key("offering"): raise sosException.SOSException( "MissingParameterValue", "offering", "Parameter \"offering\" is mandatory with multiplicity 1" ) if not requestObject.has_key("observedproperty"): raise sosException.SOSException( "MissingParameterValue", "observedProperty", "Parameter \"observedProperty\" is mandatory with multiplicity N" ) if not requestObject.has_key("responseformat"): raise sosException.SOSException( "MissingParameterValue", "responseFormat", "Parameter \"responseFormat\" is mandatory with multiplicity 1" ) #one # OPTIONAL SRS FILTER if requestObject.has_key("srsname"): try: self.srsName = get_name_from_urn( requestObject["srsname"], "refsystem", sosConfig) except Exception as e: raise sosException.SOSException( "InvalidParameterValue", "srsname", "%s" % e) if not self.srsName in sosConfig.parameters["GO_srs"]: raise sosException.SOSException( "InvalidParameterValue", "srsName", "srsName \"%s\" not supported, use one of: %s" % (self.srsName, ",".join( sosConfig.parameters["GO_srs"]))) else: self.srsName = sosConfig.parameters["GO_srs"][0] # TIME FILTER if requestObject.has_key('eventtime'): self.eventTime = [] for i in requestObject["eventtime"].replace( " ", "+").split(","): if len(i.split("/")) < 3: self.eventTime.append(i.split("/")) else: raise sosException.SOSException( "InvalidParameterValue", "eventTime", "Parameter \"eventTime\" bad formatted") # FEATURES OF INTEREST FILTER if requestObject.has_key("featureofinterest"): foi = requestObject["featureofinterest"] if foi.find("<ogc:") >= 0 and foi.find("<gml:") >= 0: self.featureOfInterestSpatial = sosUtils.ogcSpatCons2PostgisSql( foi, 'geom_foi', sosConfig.istsosepsg) else: try: self.featureOfInterest = get_name_from_urn( foi, "feature", sosConfig) except Exception as e: raise sosException.SOSException( "InvalidParameterValue", "featureofinterest", str(e)) # FILTERS FOR QUERY NOT SUPPORTED YET if requestObject.has_key("result"): self.result = sosUtils.ogcCompCons2PostgisSql( requestObject["result"]) # RESULT MODEL if requestObject.has_key("resultmodel"): if requestObject["resultmodel"] in sosConfig.parameters[ "GO_resultModel"]: self.resultModel = requestObject["resultmodel"] else: raise sosException.SOSException( "InvalidParameterValue", "resultModel", "Parameter \"resultModel\" sent with invalid value: supported values are: %s" % ",".join(sosConfig.parameters["GO_resultModel"])) else: self.resultModel = sosConfig.parameters["GO_resultModel"][ 0] # RESPONSE MODE if requestObject.has_key("responsemode"): if requestObject["responsemode"] in sosConfig.parameters[ "GO_responseMode"]: self.responseMode = requestObject["responsemode"] else: raise sosException.SOSException( "InvalidParameterValue", "responseMode", "Parameter \"responseMode\" sent with invalid value, supported values are: %s" % (",".join( sosConfig.parameters["GO_responseMode"]))) else: self.responseMode = sosConfig.parameters[ "GO_responseMode"][0] # Checking if some event limitation is reached if self.eventTime != None: tp = [] for t in self.eventTime: if len(t) == 2: tp.append(iso.parse_datetime(t[0])) tp.append(iso.parse_datetime(t[1])) if len(t) == 1: tp.append(iso.parse_datetime(t[0])) if int(sosConfig.maxGoPeriod) > 0: maxhours = timedelta(hours=int(sosConfig.maxGoPeriod)) userPeriod = max(tp) - min(tp) if maxhours < userPeriod: if self.version == '2.0.0': # REQ39 - http://www.opengis.net/spec/SOS/2.0/req/core/go-too-many-obs-exception # The service determined that the requested result set exceeds the response # size limit of the service and thus cannot be delivered. raise sosException.SOSException( "ResponseExceedsSizeLimit", "", "You are requesting data for a period of [%s hours], but you are not permitted to ask for a period longer than: %s hours" % (userPeriod, maxhours)) else: raise sosException.SOSException( "InvalidParameterValue", "eventTime", "You are requesting data for a period of [%s hours], but you are not permitted to ask for a period longer than: %s hours" % (userPeriod, maxhours)) elif (sosConfig.strictogc in ['True', 'true', 1] and self.version == '2.0.0' and self.eventTime == None and self.featureOfInterest == None and self.featureOfInterestSpatial == None and self.procedure == None): # ResponseExceedsSizeLimit fake exception raise sosException.SOSException( "ResponseExceedsSizeLimit", "", "Sorry but, You are requesting too many data") ##################################### # NON STANDARD PARAMETERS by istSOS # ##################################### # AGGREGATE INTERVAL # In ISO 8601 duration format if requestObject.has_key("aggregateinterval"): # Check on the eventTime parameter: it must be only one interval: 2010-01-01T00:00:00+00/2011-01-01T00:00:01+00 exeMsg = "Using aggregate functions, the event time must exist with an interval composed by a begin and an end date (ISO8601)" if self.eventTime == None or len(self.eventTime) != 1 or len( self.eventTime[0]) != 2: raise sosException.SOSException("InvalidParameterValue", "aggregateInterval", exeMsg) self.aggregate_interval = requestObject["aggregateinterval"] try: iso.parse_duration(self.aggregate_interval) except Exception as ex: raise sosException.SOSException( "InvalidParameterValue", "aggregateInterval", "Parameter \"aggregate_interval\" sent with invalid format (check ISO8601 duration spec): %s" % ex) else: self.aggregate_interval = None # AGGREGATE FUNCTION # sum,avg,max,min if requestObject.has_key("aggregatefunction"): if self.aggregate_interval == None: raise sosException.SOSException( "InvalidParameterValue", "aggregateFunction", "Using aggregate functions parameters \"aggregateInterval\" and \"aggregateFunction\" are both mandatory" ) self.aggregate_function = requestObject["aggregatefunction"] if not (self.aggregate_function.upper() in ["AVG", "COUNT", "MAX", "MIN", "SUM"]): raise sosException.SOSException( "InvalidParameterValue", "aggregateFunction", "Available aggregation functions: avg, count, max, min, sum." ) else: self.aggregate_function = None # AGGREGATE NODATA if requestObject.has_key("aggregatenodata"): if self.aggregate_interval == None or self.aggregate_function == None: raise sosException.SOSException( "InvalidParameterValue", "aggregateNodata", "Using aggregateNodata parameter requires both \"aggregateInterval\" and \"aggregateFunction\"" ) self.aggregate_nodata = requestObject["aggregatenodata"] else: self.aggregate_nodata = sosConfig.aggregate_nodata # AGGREGATE NODATA QUALITY INDEX if requestObject.has_key("aggregatenodataqi"): if self.aggregate_interval == None or self.aggregate_function == None: raise sosException.SOSException( "InvalidParameterValue", "aggregateNodataQi", "Using aggregateNodataQi parameter requires both \"aggregateInterval\" and \"aggregateFunction\"" ) self.aggregate_nodata_qi = requestObject["aggregatenodataqi"] else: self.aggregate_nodata_qi = sosConfig.aggregate_nodata_qi # QUALITY INDEX self.qualityIndex = False if requestObject.has_key("qualityindex"): if requestObject["qualityindex"].upper() == "TRUE": self.qualityIndex = True elif requestObject["qualityindex"].upper() == "FALSE": self.qualityIndex = False else: raise sosException.SOSException( "InvalidParameterValue", "qualityIndex", "qualityIndex can only be True or False!") # QUALITY INDEX FILTERING self.qualityFilter = False if requestObject.has_key("qualityfilter"): if len(requestObject["qualityfilter"]) >= 2: try: if requestObject["qualityfilter"][ 0:2] == '<=' or requestObject["qualityfilter"][ 0:2] == '>=': self.qualityFilter = ( requestObject["qualityfilter"][0:2], float(requestObject["qualityfilter"][2:])) elif (requestObject["qualityfilter"][0] == '>' or requestObject["qualityfilter"][0] == '=' or requestObject["qualityfilter"][0] == '<'): self.qualityFilter = ( requestObject["qualityfilter"][0], float(requestObject["qualityfilter"][1:])) # If qualityFilter is defined qualityIndex are automatically returned self.qualityIndex = True except ValueError as ve: raise sosException.SOSException( "InvalidParameterValue", "qualityFilter", "invalid quality index value in qualityFilter") else: raise sosException.SOSException( "InvalidParameterValue", "qualityFilter", "qualityFilter operator can only be in ['<','>','<=','>=','=']" ) if method == "POST": from xml.dom import minidom # THE OFFERING offs = requestObject.getElementsByTagName('offering') if len(offs) == 1: val = offs[0].firstChild if val.nodeType == val.TEXT_NODE: try: self.offering = get_name_from_urn( str(val.data), "offering", sosConfig) except Exception as e: raise sosException.SOSException( "InvalidParameterValue", "offering", str(e)) else: err_txt = "XML parsing error (get value: offering)" raise sosException.SOSException("NoApplicableCode", None, err_txt) else: err_txt = "Parameter \"offering\" is mandatory with multiplicity 1" raise sosException.SOSException("MissingParameterValue", "offering", err_txt) # THE OBSERVED PROPERTY obsProps = requestObject.getElementsByTagName('observedProperty') self.observedProperty = [] if len(obsProps) > 0: for obsProp in obsProps: val = obsProp.firstChild if val.nodeType == val.TEXT_NODE: # get_name_from_urn limit the ability to ask for an observedProperty with LIKE: # eg: ask "water" to get all the water related data, "water:discharge", "water:temperature" ... #self.observedProperty.append(get_name_from_urn(str(val.data),"property")) self.observedProperty.append(str(val.data)) else: err_txt = "XML parsing error (get value: observedProperty)" raise sosException.SOSException( "NoApplicableCode", None, err_txt) else: err_txt = "Parameter \"observedProperty\" is mandatory with multiplicity N" raise sosException.SOSException("MissingParameterValue", "observedProperty", err_txt) # RESPONSE FORMAT respF = requestObject.getElementsByTagName('responseFormat') if len(respF) == 1: val = respF[0].firstChild if val.nodeType == val.TEXT_NODE: self.responseFormat = str(val.data) if self.responseFormat not in sosConfig.parameters[ "GO_responseFormat"]: raise sosException.SOSException( "InvalidParameterValue", "responseFormat", "Parameter \"responseFormat\" sent with invalid value: use one of %s" % "; ".join( sosConfig.parameters["GO_responseFormat"])) else: err_txt = "XML parsing error (get value: responseFormat)" raise sosException.SOSException("NoApplicableCode", None, err_txt) else: err_txt = "Parameter \"responseFormat\" is mandatory with multiplicity 1" raise sosException.SOSException("MissingParameterValue", "responseFormat", err_txt) # OPTIONAL request parameters # SRS OF RETURNED GML FEATURES srs = requestObject.getAttributeNode('srsName') if srs: self.srsName = srs.nodeValue if not self.srsName in sosConfig.parameters["GO_srs"]: raise sosException.SOSException( "InvalidParameterValue", "srsName", "srsName \"%s\" not supported, use one of: %s" % (self.srsName, ",".join( sosConfig.parameters["GO_srs"]))) else: self.srsName = sosConfig.parameters["GO_srs"][0] # TIME FILTER evtms = requestObject.getElementsByTagName('eventTime') self.eventTime = [] if len(evtms) > 0: for evtm in evtms: tps = evtm.getElementsByTagName('gml:TimePeriod') for tp in tps: begin = tp.getElementsByTagName('gml:beginPosition') end = tp.getElementsByTagName('gml:endPosition') if len(begin) == 1 and len(end) == 1: Bval = begin[0].firstChild Eval = end[0].firstChild if Bval.nodeType == Bval.TEXT_NODE and Eval.nodeType == Eval.TEXT_NODE: self.eventTime.append([ str(Bval.data).replace(" ", "+"), str(Eval.data).replace(" ", "+") ]) else: err_txt = "XML parsing error (get value: TimePeriod)" raise sosException.SOSException( "NoApplicableCode", None, err_txt) tis = evtm.getElementsByTagName('gml:TimeInstant') for ti in tis: instant = ti.getElementsByTagName('gml:timePosition') if len(instant) > 0 and len(instant) < 2: Ival = instant[0].firstChild if Ival.nodeType == Ival.TEXT_NODE: self.eventTime.append( [str(Ival.data).replace(" ", "+")]) else: err_txt = "XML parsing error (get value: Timeinstant)" raise sosException.SOSException( "NoApplicableCode", None, err_txt) else: self.eventTime = None # PROCEDURES FILTER procs = requestObject.getElementsByTagName('procedure') if len(procs) > 0: self.procedure = [] for proc in procs: if "xlink:href" in proc.attributes.keys(): self.procedure.append( str(proc.getAttribute("xlink:href"))) elif proc.hasChildNodes(): val = proc.firstChild if val.nodeType == val.TEXT_NODE: try: self.procedure.append( get_name_from_urn(str(val.data), "procedure", sosConfig)) except Exception as e: raise sosException.SOSException( "InvalidParameterValue", "procedure", str(e)) else: err_txt = "XML parsing error (get value: procedure)" raise sosException.SOSException( "NoApplicableCode", None, err_txt) else: self.procedure = None # FEATURES OF INTEREST FILTER fets = requestObject.getElementsByTagName('featureOfInterest') self.featureOfInterest = None self.featureOfInterestSpatial = None # get sub-elements of FOI if fets: elements = [ e for e in fets[0].childNodes if e.nodeType == e.ELEMENT_NODE ] if len(elements) == 0: err_txt = "ObjectID or ogc:spatialOps elements in parameter \"featureOfInterest\" are mandatory" raise sosException.SOSException("NoApplicableCode", None, err_txt) # only one sub element elif len(elements) == 1 and elements[0].tagName != "ObjectID": self.featureOfInterestSpatial = sosUtils.ogcSpatCons2PostgisSql( elements[0], 'geom_foi', sosConfig.istsosepsg) else: tempfois = [] for e in elements: if not e.tagName == "ObjectID": err_txt = "Allowed only ObjectID or ogc:spatialOps elements in parameter \"featureOfInterest\"" raise sosException.SOSException( "NoApplicableCode", None, err_txt) try: val = e.firstChild if val.nodeType == val.TEXT_NODE: try: tempfois.append( get_name_from_urn( str(val.data), "feature", sosConfig)) except Exception as e: raise sosException.SOSException( "InvalidParameterValue", "featureOfInterest", str(e)) except Exception as e: raise e self.featureOfInterest = ",".join(tempfois) # FILTERS FOR QUERY NOT SUPPORTED YET ress = requestObject.getElementsByTagName('result') if len(ress) > 0: raise sosException.SOSException( "NoApplicableCode", None, "Parameter \"result\" not yet supported") else: self.result = None #zero-one optional # RESULT MODEL mods = requestObject.getElementsByTagName('resultModel') if len(mods) > 0: if len(mods) < 2: val = mods[0].firstChild if val.nodeType == val.TEXT_NODE: self.resultModel = str(val.data) if self.resultModel not in sosConfig.parameters[ "GO_resultModel"]: raise sosException.SOSException( "InvalidParameterValue", "resultModel", "Parameter \"resultModel\" sent with invalid value" ) else: err_txt = "XML parsing error (get value: resultModel)" raise sosException.SOSException( "NoApplicableCode", None, err_txt) else: err_txt = "Allowed only ONE parameter \"resultModel\"" raise sosException.SOSException("NoApplicableCode", None, err_txt) else: self.resultModel = None # RESPONSE MODE rsmods = requestObject.getElementsByTagName('responseMode') if len(rsmods) > 0: if len(rsmods) < 2: val = rsmods[0].firstChild if val.nodeType == val.TEXT_NODE: self.responseMode = str(val.data) if self.responseMode not in sosConfig.parameters[ "GO_responseMode"]: raise sosException.SOSException( "InvalidParameterValue", "responseMode", "Parameter \"responseMode\" sent with invalid value" ) else: err_txt = "XML parsing error (get value: responseMode)" raise sosException.SOSException( "NoApplicableCode", None, err_txt) else: err_txt = "Allowed only ONE parameter \"responseMode\"" raise sosException.SOSException("NoApplicableCode", None, err_txt) else: self.responseMode = sosConfig.parameters["GO_responseMode"][0] # AGGREGATE INTERVAL & FUNCTION self.aggregate_interval = None self.aggregate_function = None self.aggregate_nodata = None self.aggregate_nodata_qi = None aggint = requestObject.getElementsByTagName('aggregateInterval') aggfun = requestObject.getElementsByTagName('aggregateFunction') aggnodata = requestObject.getElementsByTagName('aggregateNodata') if len(aggint) == 1 and len(aggfun) == 1: # aggregate_interval # Check on the eventTime parameter: it must be only one interval: 2010-01-01T00:00:00+00/2011-01-01T00:00:01+00 exeMsg = "Using aggregate functions, the event time must exist with an interval composed by a begin and an end date (ISO8601)" if self.eventTime == None or len(self.eventTime) != 1 or len( self.eventTime[0]) != 2: raise sosException.SOSException("NoApplicableCode", None, exeMsg) val = aggint[0].firstChild if val.nodeType == val.TEXT_NODE: self.aggregate_interval = str(val.data) try: iso.parse_duration(self.aggregate_interval) except Exception as ex: raise sosException.SOSException( "InvalidParameterValue", "aggregateInterval", "Parameter \"aggregate_interval\" sent with invalid format (check ISO8601 duration spec): %s" % ex) else: err_txt = "cannot get ISO8601 duration value in \"aggregateInterval\"" raise sosException.SOSException("InvalidParameterValue", "aggregateInterval", err_txt) # aggregate_function val = aggfun[0].firstChild if val.nodeType == val.TEXT_NODE: self.aggregate_function = str(val.data) if not (self.aggregate_function.upper() in ["AVG", "COUNT", "MAX", "MIN", "SUM"]): raise sosException.SOSException( "InvalidParameterValue", "aggregateFunction", "Available aggregation functions: avg, count, max, min, sum." ) # aggregate_no_data default value if len(aggnodata) == 1: val = aggnodata[0].firstChild self.aggregate_nodata = str(val.data) else: self.aggregate_nodata = sosConfig.aggregate_nodata #================================ # MISSING AGGREGATE QUALITY INDEX #================================ elif len(aggint) == 0 and len(aggfun) == 0: pass else: err_txt = "\"aggregateInterval\" and \"aggregate_function\" are both required with multiplicity 1" raise sosException.SOSException("NoApplicableCode", None, err_txt) # QUALITY INDEX self.qualityIndex = False qidx = requestObject.getElementsByTagName('qualityIndex') if len(qidx) > 0: if len(qidx) < 2: val = qidx[0].firstChild if val.nodeType == val.TEXT_NODE: self.qualityIndex = str(val.data) if self.qualityIndex.upper() == "TRUE": self.qualityIndex = True elif self.qualityIndex.upper() == "FALSE": pass else: raise sosException.SOSException( "InvalidParameterValue", "qualityIndex", "qualityIndex can only be \'True\' or \'False\'" ) elif len(qidx) == 0: pass else: err_txt = "\"qualityIndex\" is allowed with multiplicity 1 only" raise sosException.SOSException("NoApplicableCode", None, err_txt) self.qualityFilter = False
def executePost(self, db=True): if self.procedurename is None: raise Exception( "POST action without procedure name not allowed") # Create data array data = self.waEnviron['wsgi_input'].split(";") # Assigned id always in the first position assignedid = data[0] if len(data) == 4: # regular time series mode = self.MODE_REGULAR start = iso.parse_datetime(data[1]) step = iso.parse_duration(data[2]) tmp_data = [] data = data[3].split("@") for idx in range(0, len(data)): tmp_data.append([ (start + (step * idx)).isoformat() ] + data[idx].split(",")) data = tmp_data elif len(data) == 2: # irregular time series mode = self.MODE_IRREGULAR data = [i.split(",") for i in data[1].split("@")] else: raise Exception( "Body content wrongly formatted. Please read the docs.") try: conn = databaseManager.PgDB( self.serviceconf.connection['user'], self.serviceconf.connection['password'], self.serviceconf.connection['dbname'], self.serviceconf.connection['host'], self.serviceconf.connection['port'] ) sql = """ SELECT procedures.id_prc, proc_obs.id_pro, proc_obs.constr_pro, procedures.stime_prc, procedures.etime_prc FROM %s.procedures, %s.proc_obs WHERE proc_obs.id_prc_fk = procedures.id_prc """ % (self.servicename, self.servicename) sql += """ AND assignedid_prc = %s ORDER BY proc_obs.id_pro ASC; """ rows = conn.select(sql, (assignedid,)) if len(rows) == 0: raise Exception( "Procedure with aid %s not found." % assignedid) # check if procedure observations length is ok if len(rows) != (len(data[0])-1): raise Exception( "Array length missmatch with procedures " "observation number") insertEventTime = """ INSERT INTO %s.event_time (id_prc_fk, time_eti) """ % (self.servicename) insertEventTime += """ VALUES (%s, %s::TIMESTAMPTZ) RETURNING id_eti; """ deleteEventTime = """ DELETE FROM %s.event_time """ % (self.servicename) deleteEventTime += """ WHERE id_prc_fk = %s AND time_eti = %s::TIMESTAMPTZ """ insertMeasure = """ INSERT INTO %s.measures( id_eti_fk, id_qi_fk, id_pro_fk, val_msr ) """ % (self.servicename) insertMeasure += """ VALUES (%s, 100, %s, %s); """ updateBeginPosition = """ UPDATE %s.procedures""" % (self.servicename) updateBeginPosition += """ SET stime_prc=%s::TIMESTAMPTZ WHERE id_prc=%s """ updateEndPosition = """ UPDATE %s.procedures""" % (self.servicename) updateEndPosition += """ SET etime_prc=%s::TIMESTAMPTZ WHERE id_prc=%s """ id_prc = rows[0][0] bp = rows[0][3] bpu = False ep = rows[0][4] epu = False for observation in data: id_eti = conn.executeInTransaction( insertEventTime, ( id_prc, observation[0])) for idx in range(0, len(rows)): conn.executeInTransaction( insertMeasure, ( int(id_eti[0][0]), # id_eti int(rows[idx][1]), # id_pro float(observation[(idx+1)]))) if (bp is None) or (bp == '') or ( iso.parse_datetime(observation[0]) < bp): bp = iso.parse_datetime(observation[0]) bpu = True if (ep is None) or (ep == '') or ( iso.parse_datetime(observation[0]) > ep): ep = iso.parse_datetime(observation[0]) epu = True if bpu: conn.executeInTransaction( updateBeginPosition, (bp.isoformat(), id_prc)) if epu: conn.executeInTransaction( updateEndPosition, (ep.isoformat(), id_prc)) conn.commitTransaction() # self.setData(ret) self.setMessage("Thanks for data") except Exception as e: traceback.print_exc(file=sys.stderr) conn.rollbackTransaction() raise Exception( "Error in fast insert (%s): %s" % (type(e), e))