Backend

Die Hauptlast bei für die Administrierung der Dienste liegt im Backend. Welche in diesem Kapitel anhand ihrer Klassen und Schichten dokumentiert werden soll.

Services

Die Services übernehmen die Instanziierung der Objekte und erstellen die vom Clienten über das Dashboard gewünschten Dienste über die REST-Schnittstelle (routes.py). Für die OGC-Dienste wurde das Factory-Pattern eingesetzt, welches je nach Parametrisierung, den entsprechenden OGC-Layer instanziiert.

OGC-Factory

Die OGC-Factory wird von der routes.py aufgerufen um die gewünschten Dienste zu erstellen. Die Factory-Pattern-Methode definiert dabei ein Interface für die Erstellung von Objekten und delegiert die Objekterstellung an die Sub-Klassen. Ziel ist, dass der Client nichts von der Objekt-Instantiierung mitbekommt und über eine gemeinsame Schnittstelle auf die Objekte zugreift. Factory-Patterns kapseln dadurch den Creation Code vom Client [Quelle].

Um dies zu verdeutlichen ist nachfolgend der Code abgebildet:

class OgcFactory:
    def __init__(self,_service):
        self.service = _service.lower()
        #localhost for testing
        if("localhost" in request.url or "127.0.0.1:5000" in request.url):
            app.logger.debug("OGC Service for localhost")
            #dummy path
            self.path ='G:\\test\\'.format(self.service)
        # server path
        else:
            app.logger.debug("OGC Service for monitor.ioer.de")
            #dummy path
            self.path = '/server/'.format(self.service)

    def create_service(self):
        if self.service =='wms':
            return WmsService(self.path)
        elif self.service =='wcs':
            return WcsService(self.path)
        elif self.service=='wfs':
            return WfsService(self.path)

Der Konstruktor definiert dabei auf welchen Pfaden die Services erstellt werden sollen.

WCS-Services

WFS-Service

WMS-Service

Die Klassen WCS-Services, WFS-Service und WMS-Service implementieren die vom OgcService-Interface definierten Methoden. Hierbei werden in der Methode createAllServices alle für die OGC-Rasterdienste bzw. Vektordienste freigegebenen Indikatoren vom Backend abgefragt. Diese Aufgabe wird von der Klasse Indicator-Values übernommen. Anhand einer Schleife wird für jeden verfügbaren Indikator ein neuer IoerIndicator instanziiert und an die writeFile Methode übergeben. Diese erstellt anhand der Getter-Methoden des übergebenen Indikators das entsprechende Mapfile in dem angegebenen Pfad. Der Pfad wird hierbei im Konstruktor übergegeben, diese Aufgabe übernimmt die Factory.

Folgend sind die Parameter und Methoden dokumentiert.

Methode Parameter Beschreibung
public: init optional-String:Path Konstruktor :wink:, Der Pfad Paramter wird bei der Verwendung der Factory durch diese übernommen
public: createAllServices Object: Indikator, optional-String:Path Methode um einzelne Dienste für einen übergebenen Indikator zu erstellen
private: writeFile optional-String:Path) Diese Methode erstellt anhand des übergebenen Indikators das gewünschte Mapfile, primär wird der Pfad aus dem im Konstruktor definierten Pfad übergeben. Als Rückgabe wird ein Objekt mit dem Indikator und dessen Status (erstellt/Fehler) übergeben.

Indicator-Values

Diese Klasse hat die Aufgabe für die Übergebene Raumgliederung alle verfügbaren Indikatoren vom Monitor-Backend abzurufen. Über die Methode getAllAvaliableServiceValues werden anhand des Paramters Raumgliederung (raster,gebiete) alle verfügbaren Indikatoren abgerufen und ein JSON-Objekt zurückgegeben. Der Code der Klasse ist nachfolgend abgebildet.

class IndicatorValues:
    def __init__(self,format):
        self.url = Config.URL_BACKEND_MONITOR
        self.json = '{"format":{"id":"%s"},"query":"getAllIndicators"}' % format
        self.format=format
        req = requests.post(self.url, data={'values':self.json})
        self.values = json.loads(req.text)
        print (self.values)

    #methon to return all possible indicator values which are possible for an indicator
    def getAllAvaliableServiceValues(self,service):
        res =[]
        for x in self.values:
            cat_name = self.values[x]['cat_name']
            cat_name_en = self.values[x]['cat_name_en']
            values = self.values[x]['indicators']
            ind_values = []
            for i in values:
                # if 1: the service is avaliable else not
                if int(values[i]["ogc"][service]) == 1:
                    ind_val=dict(values[i])
                    ind_id = dict({"id":i})
                    merge = dict()
                    merge.update(ind_id)
                    merge.update(ind_val)
                    del merge['atkis']
                    del merge['ogc']
                    ind_values.append(merge)

            res.append({'cat_id':x,'cat_name':cat_name,'cat_name_en':cat_name_en,"values":ind_values})

        return res

GeoSN

Diese Klasse implementiert das Interface GeoSN-Service und hat die Aufgabe, die Dienste des IÖR-Monitors mit dem GeoMIS zu verknüpfen. Der Service wurde notwendig, da zum aktuellen Zeitpunkt keine API auf der Seite des GeoMIS vorhanden ist, welche diese Aufgabe übernimmt.

Anhand der vom GeoMIS :email: bereitgestellten XML-Dateien, werde diese mit den aktuellen Informationen der Datenbank synchronisiert. Hierfür parst die Methode updateFile alle XML-Dateien in dem vorgegebenen Verzeichnis. Passt die Parametrisierung mit der gesetzten Klassenvariable Indikator überein, wird dieses aktualisiert. Hierfür fällt der händische Update-Vorgang in der GUI des GeoMIS weg. Durch die Freigabe des Verzeichnisses nach außen, kann das GeoMIS die in den XML-Dateien definierten Dienste harvesten.

Die Methode update ruft von Dienst Indicator-Values alle Raster und Vektor Indikatoren auf, welche das IÖR nach außen freigibt und ruft auf deren Basis die private Methode updateFile auf. Iterativ wird dabei die Klassenvariable Indikator gesetzt, welche jeweils das Model IÖR-Indikator ist.

Interfaces

Eine Schnittstelle (englisch interface) gibt in der objektorientierten Programmierung an, welche Methoden in den unterschiedlichen Klassen vorhanden sind oder vorhanden sein müssen. Quelle

OgcService

Dieses Interface definiert die notwendigen Methoden für die Erstellung eines IÖR-OGC Dienstes.

GeoSN-Service

Dieses Interface definiert die notwendigen Methoden für die Erstellung eines GeoSN Dienstes.

Indikator

Dieses Interface definiert einen Indikator für das IÖR-Indikatorensystem.

Models

Repräsentiert den internen Zustand eines Objekts und speichert alle interessanten Geschäftsdaten. Ein Model bietet Methoden an, mit denen sich der aktuelle Zustand erfragen und ändern lässt. Quelle

IÖR-Indikator

Diese Klasse wird verwendet um innerhalb der Sevices einen Indikator zu instanziieren und damit auf die getter zuzugreifen. Das Verhalten der Klasse wird dabei durch das Interaface Indikator definiert. Die Klasse besitzt auch eine Methode toJSON, welche verwendet wird um in den Service-Klassen den Status der Indikatorerstellung festzuhalten. Hierfür wird ein sogenannter state übergeben. Nachfolgend ist der Code abgebildet:

def toJSON(self,state="create"):
    return {self.id:{
            "state": state,
            "name": self.name,
            "description": self.description,
            "times": self.time_string,
            "spatial_extends": self.spatial_extends,
            "unit": self.units,
            "methodik": self.methodology
        }}

Toolbox

Die Toolbox übernimmt Aufgaben die in vielen Klassen benötigt werden. Nachfolgend ist ihr Code abgebildet.

class Toolbox:
    def clean_string(self, string):
        d = {"\\": "", "\n": "",'"':"","Kurzbeschreibung":"","  ":""}
        for i, j in d.items():
            string = string.replace(i, j)
        return string.strip()

    def json_validator(self,data):
        try:
            json.loads(data)
            return True
        except ValueError as error:
            return False
Methode Definition
clean_string Anhand eines übergebenen Strings wewrden nicht benötigte Charaktere aus diesem entfernt, dies kommt vor allem bei den langen Definitionen vor, welche von den Mapfiles nicht gelesen werden können
json_validator Prüft ob der übergebene String im JSON-Format ist, sonst wird False zurückgebenen.

Color

Die Klasse Color wird für den WMS-Service verwendet, um die Farbliche Klasseneinteilung der Mapfiles zu bewerkstelligen und um notwendige Umrechnungen durchzuführen.

Methode Paramter Rückgabe Definition
__init__ String:min_color,String:max_color,int:classes Konstruktor :wink: Bei der instanziierung der Color-Klasse muss der Minimale- und MAximale Farbwert als HEX-Code angegeben werden. Desweiteren ist es wichtig die Anzahl der Klassen zu definieren, um den Aufbauenden Berechnungen mitzuteilen, welche Breite des farbliche Spektrum besitzen soll.
private:Berechnung String:Min-Color, String:Max-Color Array Diese Methode erstellt ausgehend von der Anzhal der Klassen ein Array, welches für die übergebenen Minimal- und Maximalwerte die dazwischenliegenden Farbcodes generiert.
private:HexToRGB String:Hex-Code String:RGB-Code Diese Methode berechnet für den übergebenen Hex-Code den RGB-Wert aus
private:RGBToHex String:RGB-Code String:Hex-Code Diese Methode berechnet für den übergebenen RGB-Code den HEX-Wert aus
public:buildColorPalette   Array Diese Methode nutzt die privaten Methoden um die Finale Farbpallete zu erstellen. In dem Array wird dann für jede Klasse der entsprechende Farbwert als HEX-Code gespeichert
public: toString   String Gibt die Klassen-Paramter als String zurück

Routing

Das Route Mapping wurde für die administrativen Aufgaben implementiert. Um die Übersicht zu bewahren wurde wie auch schon für die anderen Aufgabend er API ein Blueprint angelegt, mit dem Kürzel admin, welches die URL erweitert. Nachfolgend ist der Code abgebildet, welcher demonstriert welche Klassen bei der jeweiligen URL aufgerufen werden. Die Schnittstelle ist nur für angemeldete User zu erreichen, was über die Expession @login_required realisiert wurde.

@admin.route('/')
@login_required
def admin_page():
    return render_template("admin/index.html")

@admin.route('/wfs',methods=['GET', 'POST'])
@login_required
def wfs_service():
    wfs = OgcFactory('wfs')
    return jsonify(wfs.create_service().createAllServices())

@admin.route('/wcs',methods=['POST'])
@login_required
def wcs_service():
    wcs = OgcFactory("wcs")
    return jsonify(wcs.create_service().createAllServices())

@admin.route('/wms',methods=['POST'])
@login_required
def wms_service():
    wms = OgcFactory("wms")
    return jsonify(wms.create_service().createAllServices())

@admin.route('/geosn',methods=['POST'])
@login_required
def geosn_service():
    geosn = GeoSN('/srv/www/htdocs/monitor_ogc_xml/')
    return jsonify(geosn.update())

In der nachfolgenden Tabelle sind die URL-Endpoints und deren Aufgaben kurz zusammengefasst.

Endpoint Beschreibung
/admin/ beim Aufruf dieser URL wird das zugrundeliegende Template aus dem Static gerendert (admin/index.html).
/admin/wfs Hier wird der OGC-Factory als Service wfs mitgegeben, wodruch alle Web Feature Services des IÖR aktualisiert werden.
/admin/wcs Hier wird der OGC-Factory als Service wcs mitgegeben, wodruch alle Web Coverage Services des IÖR aktualisiert werden.
/admin/wms Hier wird der OGC-Factory als Service wms mitgegeben, wodruch alle Web Map Services des IÖR aktualisiert werden.
/admin/geosn Hier wird die Klasse GeoSN aufgerufen, womit alle Dienste des IÖR im GeoMIS aktualisiert werden.